diff -u --recursive --new-file v2.1.111/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.111/linux/Documentation/Configure.help	Sun Jul 26 11:57:14 1998
+++ linux/Documentation/Configure.help	Sun Jul 26 23:40:27 1998
@@ -1488,6 +1488,76 @@
   If you want to play with it, say Y here and to the driver for your
   graphics board, below. If unsure, say N.
 
+Acorn VIDC support
+CONFIG_FB_ACORN
+  This is the frame buffer device driver for the Acorn VIDC graphics
+  chipset.
+
+Apollo frame buffer device
+CONFIG_FB_APOLLO
+  This is the frame buffer device driver for the monochrome graphics
+  hardware found in some Apollo workstations.
+
+Amiga native chipset support
+CONFIG_FB_AMIGA
+  This is the frame buffer device driver for the builtin graphics
+  chipset found in Amigas.
+
+Amiga OCS chipset support
+CONFIG_FB_AMIGA_OCS
+  This enables support for the original Agnus and Denise video chips,
+  found in the Amiga 1000 and most A500's and A2000's.  If you intend
+  to run Linux on any of these systems, say Y; otherwise say N.
+
+Amiga ECS chipset support
+CONFIG_FB_AMIGA_ECS
+  This enables support for the Enhanced Chip Set, found in later
+  A500's, later A2000's, the A600, the A3000, the A3000T and CDTV.  If
+  you intend to run Linux on any of these systems, say Y; otherwise
+  say N.
+
+Amiga AGA chipset support
+CONFIG_FB_AMIGA_AGA
+  This enables support for the Advanced Graphics Architecture (also
+  known as the AGA or AA) Chip Set, found in the A1200, A4000, A4000T
+  and CD32.  If you intend to run Linux on any of these systems, say Y;
+  otherwise say N.
+
+Amiga CyberVision support
+CONFIG_FB_CYBER
+  This enables support for the Cybervision 64 graphics card from Phase5.
+  Please note that its use is not all that intuitive (i.e. if you have
+  any questions, be sure to ask!).  Say N unless you have a Cybervision
+  64 or plan to get one before you next recompile the kernel.         
+  Please note that this driver DOES NOT support the Cybervision 64 3D
+  card, as they use incompatible video chips.           
+
+Amiga CyberVision3D support (EXPERIMENTAL)
+CONFIG_FB_VIRGE
+  This enables support for the Cybervision 64/3D graphics card from Phase5.
+  Please note that its use is not all that intuitive (i.e. if you have
+  any questions, be sure to ask!).  Say N unless you have a Cybervision
+  64/3D or plan to get one before you next recompile the kernel.         
+  Please note that this driver DOES NOT support the older Cybervision 64
+  card, as they use incompatible video chips.           
+
+Amiga RetinaZ3 support (EXPERIMENTAL)
+CONFIG_FB_RETINAZ3
+  This enables support for the Retina Z3 graphics card. Say N unless you
+  have a Retina Z3 or plan to get one before you next recompile the kernel.
+
+Amiga CLgen driver (EXPERIMENTAL)
+CONFIG_FB_CLGEN
+  This enables support for Cirrus Logic GD542x/543x based boards on Amiga:
+  SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum.  Say N
+  unless you have such a graphics board or plan to get one before you next
+  recompile the kernel.
+
+Atari native chipset support
+CONFIG_FB_ATARI
+  This is the frame buffer device driver for the builtin graphics
+  chipset found in Ataris.
+
 Open Firmware frame buffer device support 
 CONFIG_FB_OF
   Say Y if you want support with Open Firmware for your graphics board.
@@ -1500,6 +1570,31 @@
 CONFIG_FB_ATY
   This driver supports graphics boards with the ATI Mach64 chips.
 
+PowerMac "control" frame buffer device support
+CONFIG_FB_CONTROL
+  This driver supports a frame buffer for the graphics adapter in the
+  Power Macintosh 7300 and others.
+
+PowerMac "platinum" frame buffer device support
+CONFIG_FB_PLATINUM
+  This driver supports a frame buffer for the "platinum" graphics adapter
+  in some Power Macintoshes.
+
+Chips 65550 display support
+CONFIG_FB_CT65550
+  This is the frame buffer device driver for the Chips & Technologies
+  65550 graphics chip in PowerBooks.
+
+Mac frame buffer device
+CONFIG_FB_MAC
+  This is the frame buffer device driver for the graphics hardware in
+  m68k Macintoshes.
+
+HP300 frame buffer device
+CONFIG_FB_HP300
+  This is the frame buffer device driver for the Topcat graphics
+  hardware found in HP300 workstations.
+
 VGA chipset support (text only)
 CONFIG_FB_VGA
   This is the frame buffer device driver for generic VGA chips. This
@@ -1530,38 +1625,143 @@
   
   If unsure, say N.
 
-###
-### Somebody please explain the following options
-###
-# Virtual Frame Buffer support (ONLY FOR TESTING!)
-# CONFIG_FB_VIRTUAL
-#
-# Advanced low level driver options
-# CONFIG_FBCON_ADVANCED
-#
-# Monochrome support
-# CONFIG_FBCON_MFB
-#
-# 2 bpp packed pixels support
-# CONFIG_FBCON_CFB2
-#
-# 4 bpp packed pixels support
-# CONFIG_FBCON_CFB4
-#
-# 8 bpp packed pixels support
-# CONFIG_FBCON_CFB8
-#
-# 16 bpp packed pixels support
-# CONFIG_FBCON_CFB16
-#
-# 24 bpp packed pixels support
-# CONFIG_FBCON_CFB24
-#
-# 32 bpp packed pixels support
-# CONFIG_FBCON_CFB32
-#
-# VGA characters/attributes support
-# CONFIG_FBCON_VGA
+SBUS and UPA framebuffers
+CONFIG_FB_SBUS
+  Say Y if you want support for SBUS or UPA based frame buffer device.
+
+Creator/Creator3D support
+CONFIG_FB_CREATOR
+  This is the frame buffer device driver for the Creator and Creator3D
+  graphics boards.
+
+CGsix (GX,TurboGX) support
+CONFIG_FB_CGSIX
+  This is the frame buffer device driver for the CGsix (GX, TurboGX)
+  frame buffer.
+
+BWtwo support
+CONFIG_FB_BWTWO
+  This is the frame buffer device driver for the BWtwo frame buffer.
+
+CGthree support
+CONFIG_FB_CGTHREE
+  This is the frame buffer device driver for the CGthree frame buffer.
+
+TCX (SS4/SS5 only) support
+CONFIG_FB_TCX
+  This is the frame buffer device driver for the TCX 24/8bit frame buffer.
+
+Virtual Frame Buffer support (ONLY FOR TESTING!)
+CONFIG_FB_VIRTUAL
+  This is a `virtual' frame buffer device.  It operates on a chunk of
+  unswapable kernel memory instead of on the memory of a graphics board.
+  This means you cannot see any output sent to this frame buffer device,
+  while it does consume precious memory.  The main use of this frame
+  buffer device is testing and debugging the frame buffer subsystem. Do
+  NOT enable it for normal systems! To protect the innocent, it has to
+  be enabled explicitly on boot time using the kernel option `video=vfb:'.
+
+  This driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want).
+  The module will be called vfb.o.  If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
+ 
+  If unsure, say N.
+
+Advanced low level driver options
+CONFIG_FBCON_ADVANCED
+  The frame buffer console uses character drawing routines that are
+  tailored to the specific organization of pixels in the memory of your
+  graphics hardware.  These are called the low level frame buffer console
+  drivers. Note that they are used for text console output only; they are
+  NOT needed for graphical applications.
+
+  If you do not enable this option, the needed low level drivers are
+  automatically enabled, depending on what frame buffer devices you
+  selected. This is recommended for most users.
+
+  If you enable this option, you have more fine-grained control over which
+  low level drivers are enabled. You can e.g. leave out low level drivers
+  for color depths you do not intend to use for text consoles.
+
+  Low level frame buffer console drivers can be modules ( = code which
+  can be inserted and removed from the running kernel whenever you want).
+  The modules will be called fbcon-*.o.  If you want to compile (some of)
+  them as modules, read Documentation/modules.txt.
+  
+  If unsure, say N.
+
+Monochrome support
+CONFIG_FBCON_MFB
+  This is the low level frame buffer console driver for monochrome
+  (2 colors) packed pixels.
+
+2 bpp packed pixels support
+CONFIG_FBCON_CFB2
+  This is the low level frame buffer console driver for 2 bits per pixel
+  (4 colors) packed pixels.
+
+4 bpp packed pixels support
+CONFIG_FBCON_CFB4
+  This is the low level frame buffer console driver for 4 bits per pixel
+  (16 colors) packed pixels.
+
+8 bpp packed pixels support
+CONFIG_FBCON_CFB8
+  This is the low level frame buffer console driver for 8 bits per pixel
+  (256 colors) packed pixels.
+
+16 bpp packed pixels support
+CONFIG_FBCON_CFB16
+  This is the low level frame buffer console driver for 15 or 16 bits
+  per pixel (32K or 64K colors, also known as `hicolor') packed pixels.
+
+24 bpp packed pixels support
+CONFIG_FBCON_CFB24
+  This is the low level frame buffer console driver for 24 bits per
+  pixel (16M colors, also known as `truecolor') packed pixels. It is
+  NOT for `sparse' 32 bits per pixel mode.
+
+32 bpp packed pixels support
+CONFIG_FBCON_CFB32
+  This is the low level frame buffer console driver for 32 bits per pixel
+  (16M colors, also known as `truecolor') sparse packed pixels.
+
+Amiga bitplanes support
+CONFIG_FBCON_AFB
+  This is the low level frame buffer console driver for 1 to 8 bitplanes
+  (2 to 256 colors) on Amiga.
+
+Amiga interleaved bitplanes support
+CONFIG_FBCON_ILBM
+  This is the low level frame buffer console driver for 1 to 8
+  interleaved bitplanes (2 to 256 colors) on Amiga.
+
+Atari interleaved bitplanes (2 planes) support
+CONFIG_FBCON_IPLAN2P2
+  This is the low level frame buffer console driver for 2 interleaved
+  bitplanes (4 colors) on Atari.
+
+Atari interleaved bitplanes (4 planes) support
+CONFIG_FBCON_IPLAN2P4
+  This is the low level frame buffer console driver for 4 interleaved
+  bitplanes (16 colors) on Atari.
+
+Atari interleaved bitplanes (8 planes) support
+CONFIG_FBCON_IPLAN2P8
+  This is the low level frame buffer console driver for 8 interleaved
+  bitplanes (256 colors) on Atari.
+
+Mac variable bpp packed pixels support
+CONFIG_FBCON_MAC
+  This is the low level frame buffer console driver for 1/2/4/8/16/32
+  bits per pixel packed pixels on Mac. It supports variable fontwidths
+  for low resolution screens.
+  
+VGA characters/attributes support
+CONFIG_FBCON_VGA
+  This is the low level frame buffer console driver for VGA text mode, as
+  used by vgafb.
 
 Parallel-port support
 CONFIG_PARPORT
@@ -5783,18 +5983,6 @@
   The module will be called isp16.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-Preload dcache
-CONFIG_DCACHE_PRELOAD
-  Preloading will create dcache entries when a directory is scanned
-  (e.g. because the ls command was used) for the *first* time. This
-  should speed up successive lookups of information about files in
-  that directory, but can also consume large amounts of memory.
-
-  Please report speedups (or slowdowns due to the memory usage if they
-  occur) to schoebel@informatik.uni-stuttgart.de .
-
-  If unsure, say N.
-
 Quota support
 CONFIG_QUOTA
   If you say Y here, you will be able to set per user limits for disk
@@ -5804,173 +5992,6 @@
   (user: anonymous) in
   ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini. Probably the quota
   support is only useful for multi user systems. If unsure, say N.
-
-Online mirror support
-CONFIG_OMIRR
-  omirr is a package for _symmetric_ mirroring of files over the
-  Internet. In contrast to rdist, the online mirror daemon (omirrd) is
-  running all the time and transfers any changes on the file system as
-  soon as possible to all other servers. Symmetric means that all
-  servers have equal rights in changing a file: the last changer of a
-  file will win. This is the same behaviour as multiple processes
-  operating on a global file system. In effect, omirr can do the same
-  as NFS mounts, but will have better performance since the data is
-  stored on local disks. In contrast to a cache filesystem which has a
-  dedicated master copy, broken connections and/or servers are no
-  problem for continuing work on the remaining ones, because there is
-  no master copy. Every computer that wants to participate in the
-  mirroring needs to run the daemon omirrd, contained in the omirr
-  package which is available via FTP (user: anonymous) from
-  ftp://ftp.isa.de/pub/home/luik. You must say Y if you want to use
-  in.omirrd, but you should (but need not) say N if you don't (for
-  performance reasons).
-
-  Note that this is experimental code; use at your own risk.
-
-Filename translation support
-CONFIG_TRANS_NAMES
-  This is a useful feature if you have a pool of diskless Linux
-  clients which mount their root filesystems from a central
-  server. Depending on their hostnames, the clients can then see
-  different versions of certain files, which keeps maintenance at a
-  minimum when used for configuration files. The kernel running on the
-  clients should have this option enabled. If you don't administer a
-  pool of Linux clients, say N here, otherwise read on:
-
-  When you say Y here, filenames, directory names etc become
-  context-sensitive.  If you have a file named
-  "/etc/config#host=banana#", it will appear (by default) as
-  hardlinked to "/etc/config" on host "banana", while on host "mango"
-  another file "/etc/config#host=mango#" will appear as having been
-  hardlinked to "/etc/config".
-  This default behaviour can be changed by setting the _first_
-  environment variable NAMETRANS to a colon-separated list of suffixes
-  which are tried in the specified order. For example, in 
- 
-  'env - NAMETRANS=#host=mango#:#ktype=diskless# "`env`" command ...'
-   
-  the command will see the same files as if it had been executed on
-  host "mango" with a diskless kernel.
-
-  Using NAMETRANS supersedes _all_ default translations. Thus
-  translations can be completely switched off with an empty list,
-  e.g. 
-
-  'env - NAMETRANS= "`env`" command ...'  
-
-  Note that some system utilities like tar, dump, restore should be
-  used with translation switched off, in order to avoid doubled space
-  in archive files and when extracting from them. Also, make sure that
-  nfsd, mountd (and similar ones like samba daemons) run without
-  translation, in order to avoid doubled (or even wrong) translation
-  at the server and at the client.
-
-  You can automatically force the creation of context-dependent
-  filenames if there exists a template filename like
-  "/etc/mtab#host=CREATE#". As soon as a process running on "mango"
-  tries to create a file "/etc/mtab", the version
-  "/etc/mtab#host=mango#" is created instead (which appears in turn as
-  hardlinked to "/etc/mtab").  Note that if you want to make
-  "/etc/fstab" context-dependent, you should execute "touch
-  /etc/mtab#host=CREATE#" and "touch /etc/mtab.tmp#host=CREATE#",
-  because mount, umount and others running on different hosts would
-  otherwise try to create one shared /etc/mtab which would result in a
-  clash. Also one should execute "touch /etc/nologin#host=CREATE#" to
-  prevent global side effects from shutdown resp. runlevel.
-
-  Please read Documentation/transname.txt if you intend to say Y here.
-
-Restrict translation to gid
-CONFIG_TRANS_RESTRICT
-  If you say Y here, default filename translations are carried out
-  only if the parent directory of the context-sensitive file belongs
-  to a specific group id (gid). Trying to translate names everywhere
-  will decrease performance of file openings. Normally translations
-  are used only in system configuration files but not in ordinary user
-  file space. So you should change the gid of directories containing
-  context-dependent files to some special group like "adm" (group id
-  4) and enable this option. As a result, users will not notice any
-  performance degradation resulting from filename translation.
-
-  Note that translations resulting from the first environment variable
-  "NAMETRANS=..." are always carried out regardless of the gid of
-  directories.
-
-  Beware: before turning on this option make sure that all directories
-  containing context-dependent files belong to the special group, or
-  system initialization may fail. If unsure, select N.
-
-Group id (gid) for translation restriction
-CONFIG_TRANS_GID
-  Default name translations will be carried out only inside directories
-  belonging to the group id (gid) that you specify here.
-  Default is 4 (group "adm").
-
-Nodename (hostname) translation
-CONFIG_TR_NODENAME
-  Enables translation of name suffixes like in
-  "/etc/config#host=banana#".  The syntax is
-  <filename>#host=<hostname>#. The hostname can be queried with the
-  command "uname -n". Normally this option is used heavily when
-  translation is enabled. If unsure, say Y.
-
-Kernelname translation
-CONFIG_TR_KERNNAME
-  Enables translation of name suffixes like in
-  "/etc/config#kname=default#".  The string is hard compiled into the
-  kernel by the following option.  Useful if your kernel does not know
-  the hostname at boot time, and there is no way to tell the hostname
-  by lilo or bootp. Please avoid using this option and prefer
-  "Nodename (hostname) translation" (CONFIG_TR_NODENAME) wherever
-  possible. When mounting the root over NFS, the own hostname must be
-  known at boot time anyway; this option is just for special use.
-  Note that the default translations are tried in the order as
-  occurring in the configuration, that is 1) host 2) kname 3) ktype 4)
-  machine 5) system. If unsure, say Y.
-
-String for kernelname translation
-CONFIG_KERNNAME
-  Enter the string you want to compile into the kernel. The string
-  will be used as context in context-dependent files like
-  "/etc/config#kname=<string>#".
-
-Kerneltype translation
-CONFIG_TR_KERNTYPE
-  Enables translation of name suffixes like in
-  "/etc/config#ktype=default#".  The syntax is
-  <filename>#ktype=<string>#. The string is hard compiled in the
-  kernel by the following option. Use if you want to create different
-  kernels with different behaviour. For example, use the string
-  "default" on your server, and use "diskless" on all your diskless
-  clients (and perhaps "dataless" on dataless clients). This way you
-  can avoid dozens of "config#host=<something># with same contents and
-  you have no effort when new machines are added. If unsure, say Y.
-
-String for kerneltype translation
-CONFIG_KERNTYPE
-  Enter the string you want to compile into the kernel. The string
-  will be used as context in context-dependent files like
-  "/etc/config#ktype=default#". If your kernel is to be used on a
-  server, you probably can use "default" here. If your kernel is
-  intended for a diskless client, you probably should enter "diskless"
-  here.
-
-Machine type translation
-CONFIG_TR_MACHINE
-  Enables translation of name suffixes like in
-  "/etc/config#machine=i486#".  The syntax is
-  <filename>#machine=<id>#. The machine types can be queried with the
-  command "uname -m". Normally used only on multi-architecture
-  installations. If unsure, say Y.
-
-System name translation
-CONFIG_TR_SYSNAME
-  Enables translation of name suffixes like in
-  "/etc/config#system=Linux#".  The syntax is
-  <filename>#system=<id>#. The system name can be queried with the
-  command "uname -s". Currently only supported by Linux, but hopefully
-  other operating systems will pick up the idea of context-dependent
-  translations. If unsure, say Y.
 
 Minix fs support
 CONFIG_MINIX_FS
diff -u --recursive --new-file v2.1.111/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.111/linux/MAINTAINERS	Tue Jul 21 00:15:29 1998
+++ linux/MAINTAINERS	Sun Jul 26 23:35:55 1998
@@ -310,6 +310,12 @@
 W:	http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html
 S:	Maintained
 
+IP FIREWALL
+P:	Paul Russell
+M:	Paul.Russell@rustcorp.com.au
+W:	http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html
+S:	Maintained
+
 IPX/SPX NETWORK LAYER
 P:	Jay Schulist
 M:	Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
@@ -325,6 +331,7 @@
 JOYSTICK DRIVER
 P:	Vojtech Pavlik
 M:	vojtech@atrey.karlin.mff.cuni.cz
+W:	http://atrey.karlin.mff.cuni.cz/~vojtech/joystick/
 L:	linux-joystick@atrey.karlin.mff.cuni.cz
 S:	Maintained
 
@@ -555,6 +562,12 @@
 M:	R.E.Wolff@BitWizard.nl
 M:	io8-linux@specialix.co.uk
 L:	linux-kernel@vger.rutgers.edu ?
+S:	Supported
+
+SPX NETWORK LAYER
+P:	Jay Schulist
+M:	Jay.Schulist@spacs.k12.wi.us
+L:	linux-net@vger.rutgers.edu
 S:	Supported
 
 SPX NETWORK LAYER
diff -u --recursive --new-file v2.1.111/linux/Makefile linux/Makefile
--- v2.1.111/linux/Makefile	Sun Jul 26 11:57:14 1998
+++ linux/Makefile	Sun Jul 26 14:40:18 1998
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 111
+SUBLEVEL = 112
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
@@ -298,7 +298,7 @@
 	cd modules; \
 	MODULES=""; \
 	inst_mod() { These="`cat $$1`"; MODULES="$$MODULES $$These"; \
-		mkdir -p $$MODLIB/$$2; cp -p $$These $$MODLIB/$$2; \
+		mkdir -p $$MODLIB/$$2; cp $$These $$MODLIB/$$2; \
 		echo Installing modules under $$MODLIB/$$2; \
 	}; \
 	\
@@ -340,7 +340,8 @@
 	rm -f core `find . -name '.*.flags' -print`
 	rm -f vmlinux System.map
 	rm -f .tmp*
-	rm -f drivers/char/consolemap_deftbl.c drivers/char/conmakehash
+	rm -f drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c
+	rm -f drivers/char/conmakehash
 	rm -f drivers/sound/bin2hex drivers/sound/hex2hex
 	if [ -d modules ]; then \
 		rm -f core `find modules/ -type f -print`; \
diff -u --recursive --new-file v2.1.111/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v2.1.111/linux/arch/alpha/kernel/traps.c	Tue Feb 17 13:12:44 1998
+++ linux/arch/alpha/kernel/traps.c	Mon Jul 27 18:23:41 1998
@@ -13,12 +13,12 @@
 #include <linux/sched.h>
 #include <linux/tty.h>
 #include <linux/delay.h>
+#include <linux/smp_lock.h>
 
 #include <asm/gentrap.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 #include <asm/sysinfo.h>
-#include <asm/smp_lock.h>
 
 
 static void dik_show_regs(struct pt_regs *regs, unsigned long *r9_15)
diff -u --recursive --new-file v2.1.111/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c
--- v2.1.111/linux/arch/i386/kernel/bios32.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/i386/kernel/bios32.c	Mon Jul 27 11:44:56 1998
@@ -1,7 +1,7 @@
 /*
  * bios32.c - Low-Level PCI Access
  *
- * $Id: bios32.c,v 1.40 1998/07/16 21:16:03 mj Exp $
+ * $Id: bios32.c,v 1.42 1998/07/26 09:33:07 mj Exp $
  *
  * Copyright 1993, 1994 Drew Eckhardt
  *      Visionary Computing
@@ -86,7 +86,6 @@
 #include "irq.h"
 
 #undef DEBUG
-#define DEBUG
 
 #ifdef DEBUG
 #define DBG(x...) printk(x)
@@ -914,29 +913,31 @@
  * Although several sources claim that the host bridges should have
  * header type 1 and be assigned a bus number as for PCI2PCI bridges,
  * the reality doesn't pass this test and the bus number is usually
- * hard-wired to 1.
+ * set by BIOS to the first free value.
  */
 __initfunc(void pcibios_fixup_peer_bridges(void))
 {
-	struct pci_dev *dev;
-	int cnt = 0;
+	struct pci_bus *b = &pci_root;
+	int i;
 
-	for(dev=pci_root.devices; dev; dev=dev->sibling)
-		if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) {
-			DBG("PCI: Host bridge at %02x\n", dev->devfn);
-			if (cnt) {
-				struct pci_bus *b = kmalloc(sizeof(struct pci_bus), GFP_KERNEL);
+	do {
+		int n = b->subordinate+1;
+		u16 l;
+		for(i=0; i<256; i += 8)
+			if (!pcibios_read_config_word(n, i, PCI_VENDOR_ID, &l) &&
+			    l != 0x0000 && l != 0xffff) {
+				DBG("Found device at %02x:%02x\n", n, i);
+				printk("PCI: Discovered primary peer bus %02x\n", n);
+				b = kmalloc(sizeof(*b), GFP_KERNEL);
 				memset(b, 0, sizeof(*b));
-				b->parent = &pci_root;
 				b->next = pci_root.next;
 				pci_root.next = b;
-				b->self = dev;
-				b->number = b->secondary = cnt;
+				b->number = b->secondary = n;
 				b->subordinate = 0xff;
 				b->subordinate = pci_scan_bus(b);
+				break;
 			}
-			cnt++;
-		}
+	} while (i < 256);
 }
 
 /*
diff -u --recursive --new-file v2.1.111/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.1.111/linux/arch/i386/kernel/i386_ksyms.c	Thu Jul 16 18:09:23 1998
+++ linux/arch/i386/kernel/i386_ksyms.c	Mon Jul 27 17:43:30 1998
@@ -20,7 +20,6 @@
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu(elf_fpregset_t *);
-extern void __lock_kernel(void);
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
 extern struct drive_info_struct drive_info;
@@ -68,11 +67,8 @@
 
 #ifdef __SMP__
 EXPORT_SYMBOL(cpu_data);
-EXPORT_SYMBOL_NOVERS(kernel_flag);
-EXPORT_SYMBOL_NOVERS(active_kernel_processor);
+EXPORT_SYMBOL(kernel_flag);
 EXPORT_SYMBOL(smp_invalidate_needed);
-EXPORT_SYMBOL_NOVERS(__lock_kernel);
-EXPORT_SYMBOL(lk_lockmsg);
 EXPORT_SYMBOL(__cpu_logical_map);
 EXPORT_SYMBOL(smp_num_cpus);
 
diff -u --recursive --new-file v2.1.111/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
--- v2.1.111/linux/arch/i386/kernel/io_apic.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/i386/kernel/io_apic.c	Sun Jul 26 13:24:05 1998
@@ -966,21 +966,6 @@
 	mask_IO_APIC_irq(irq);
 }
 
-/*
- * Enter and exit the irq handler context..
- */
-static inline void enter_ioapic_irq(int cpu)
-{
-	hardirq_enter(cpu);
-	while (test_bit(0,&global_irq_lock)) barrier();
-}
-
-static inline void exit_ioapic_irq(int cpu)
-{
-	hardirq_exit(cpu);
-	release_irqlock(cpu);
-}	
-
 static void do_edge_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs)
 {
 	irq_desc_t *desc = irq_desc + irq;
@@ -1014,7 +999,7 @@
 	if (!action)
 		return;
 
-	enter_ioapic_irq(cpu);
+	irq_enter(cpu, irq);
 
 	/*
 	 * Edge triggered interrupts need to remember
@@ -1035,7 +1020,7 @@
 	desc->status &= IRQ_DISABLED;
 	spin_unlock(&irq_controller_lock);
 
-	exit_ioapic_irq(cpu);
+	irq_exit(cpu, irq);
 }
 
 static void do_level_ioapic_IRQ (unsigned int irq, int cpu,
@@ -1074,7 +1059,7 @@
 	if (!action)
 		return;
 
-	enter_ioapic_irq(cpu);
+	irq_enter(cpu, irq);
 
 	handle_IRQ_event(irq, regs);
 
@@ -1084,7 +1069,7 @@
 		unmask_IO_APIC_irq(irq);
 	spin_unlock(&irq_controller_lock);
 
-	exit_ioapic_irq(cpu);
+	irq_exit(cpu, irq);
 }
 
 /*
diff -u --recursive --new-file v2.1.111/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c
--- v2.1.111/linux/arch/i386/kernel/mtrr.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/i386/kernel/mtrr.c	Mon Jul 27 21:31:06 1998
@@ -138,6 +138,7 @@
 #define MTRR_NEED_STRINGS
 #include <asm/mtrr.h>
 #include <linux/init.h>
+#include <linux/smp.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -146,9 +147,7 @@
 #include <asm/pgtable.h>
 #include <asm/segment.h>
 #include <asm/bitops.h>
-#include <asm/smp_lock.h>
 #include <asm/atomic.h>
-#include <linux/smp.h>
 
 #define MTRR_VERSION            "1.22 (19980611)"
 
diff -u --recursive --new-file v2.1.111/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.1.111/linux/arch/i386/kernel/smp.c	Sun Jul 26 11:57:15 1998
+++ linux/arch/i386/kernel/smp.c	Mon Jul 27 17:42:59 1998
@@ -100,8 +100,15 @@
  */
 
 
+/* Kernel spinlock */
+spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+
 /*
  *	Why isn't this somewhere standard ??
+ *
+ * Maybe because this procedure is horribly buggy, and does
+ * not deserve to live.  Think about signedness issues for five
+ * seconds to see why.		- Linus
  */
 
 extern __inline int max(int a,int b)
@@ -135,8 +142,6 @@
 
 static volatile unsigned char smp_cpu_in_msg[NR_CPUS];	/* True if this processor is sending an IPI		*/
 
-volatile unsigned long kernel_flag=0;			/* Kernel spinlock 					*/
-volatile unsigned char active_kernel_processor = NO_PROC_ID;	/* Processor holding kernel spinlock		*/
 volatile unsigned long kernel_counter=0;		/* Number of times the processor holds the lock		*/
 volatile unsigned long syscall_count=0;			/* Number of times the processor holds the syscall lock	*/
 
@@ -990,7 +995,6 @@
 
 	cpu_present_map |= (1 << hard_smp_processor_id());
 	cpu_number_map[boot_cpu_id] = 0;
-	active_kernel_processor=boot_cpu_id;
 
 	/*
 	 *	If we don't conform to the Intel MPS standard, get out
@@ -1364,12 +1368,6 @@
 {
 	unsigned long flags;
 
-#if 0
-	if(smp_activated && smp_processor_id()!=active_kernel_processor) {
-		printk("CPU #%d:Attempted flush tlb IPI when not AKP(=%d)\n",smp_processor_id(),active_kernel_processor);
-		*(char *)0=0;
-	}
-#endif
 /*	printk("SMI-");*/
 
 	/*
@@ -1412,7 +1410,7 @@
 
 	__save_flags(flags);
 	__cli();
-	smp_message_pass(cpu, MSG_RESCHEDULE, 0L, 2);
+	smp_message_pass(cpu, MSG_RESCHEDULE, 0L, 0);
 	__restore_flags(flags);
 }
 
diff -u --recursive --new-file v2.1.111/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile
--- v2.1.111/linux/arch/i386/lib/Makefile	Tue Jul 21 00:15:30 1998
+++ linux/arch/i386/lib/Makefile	Mon Jul 27 15:28:57 1998
@@ -6,6 +6,6 @@
 	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
 
 L_TARGET = lib.a
-L_OBJS  = checksum.o semaphore.o locks.o delay.o usercopy.o getuser.o putuser.o
+L_OBJS  = checksum.o semaphore.o delay.o usercopy.o getuser.o putuser.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.111/linux/arch/i386/lib/locks.S linux/arch/i386/lib/locks.S
--- v2.1.111/linux/arch/i386/lib/locks.S	Wed Jun 24 22:54:03 1998
+++ linux/arch/i386/lib/locks.S	Wed Dec 31 16:00:00 1969
@@ -1,36 +0,0 @@
-/* locks.S: Wheee... I'm coding Intel assembly...
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/linkage.h>
-
-	/* Caller does atomic increment on current->lock_depth,
-	 * if it was found to originally be zero then we get here,
-	 * %eax contains caller's PC and %edx holds this CPU ID.
-	 */
-ENTRY(__lock_kernel)
-1:
-	lock
-	btsl	$0, SYMBOL_NAME(kernel_flag)
-	jnc	3f
-	sti
-2:
-	btl	%edx, SYMBOL_NAME(smp_invalidate_needed)
-	jnc	0f
-	lock
-	btrl	%edx, SYMBOL_NAME(smp_invalidate_needed)
-	jnc	0f
-	pushl	%eax
-	movl	%cr3, %eax
-	movl	%eax, %cr3
-	popl	%eax
-0:
-	btl	$0, SYMBOL_NAME(kernel_flag)
-	jc	2b
-	cli
-	jmp	1b
-
-3:
-	movb	%dl, SYMBOL_NAME(active_kernel_processor)
-	ret
diff -u --recursive --new-file v2.1.111/linux/arch/i386/mm/ioremap.c linux/arch/i386/mm/ioremap.c
--- v2.1.111/linux/arch/i386/mm/ioremap.c	Fri Apr  4 08:52:17 1997
+++ linux/arch/i386/mm/ioremap.c	Sun Jul 26 14:28:07 1998
@@ -90,13 +90,34 @@
 	void * addr;
 	struct vm_struct * area;
 
-	if (phys_addr < virt_to_phys(high_memory))
+	/*
+	 * Don't remap the low PCI/ISA area, it's always mapped..
+	 */
+	if (phys_addr >= 0xA0000 && (phys_addr+size) <= 0x100000)
 		return phys_to_virt(phys_addr);
+
+	/*
+	 * Don't allow anybody to remap normal RAM that we're using..
+	 */
+	if (phys_addr < virt_to_phys(high_memory))
+		return NULL;
+
+	/*
+	 * Mappings have to be page-aligned
+	 */
 	if (phys_addr & ~PAGE_MASK)
 		return NULL;
 	size = PAGE_ALIGN(size);
+
+	/*
+	 * Don't allow mappings that wrap..
+	 */
 	if (!size || size > phys_addr + size)
 		return NULL;
+
+	/*
+	 * Ok, go for it..
+	 */
 	area = get_vm_area(size);
 	if (!area)
 		return NULL;
diff -u --recursive --new-file v2.1.111/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c
--- v2.1.111/linux/drivers/block/ide-floppy.c	Thu May  7 22:51:48 1998
+++ linux/drivers/block/ide-floppy.c	Sun Jul 26 11:46:46 1998
@@ -43,6 +43,7 @@
 #include <linux/errno.h>
 #include <linux/genhd.h>
 #include <linux/malloc.h>
+#include <linux/cdrom.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -1141,7 +1142,18 @@
 static int idefloppy_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
 				 unsigned int cmd, unsigned long arg)
 {
-	return -EIO;
+	idefloppy_pc_t pc;
+
+	if (cmd == CDROMEJECT) {
+		if (drive->usage > 1)
+			return -EBUSY;
+		idefloppy_create_prevent_cmd (&pc, 0);
+		(void) idefloppy_queue_pc_tail (drive, &pc);
+		idefloppy_create_start_stop_cmd (&pc, 2);
+		(void) idefloppy_queue_pc_tail (drive, &pc);
+		return 0;
+	}
+ 	return -EIO;
 }
 
 /*
diff -u --recursive --new-file v2.1.111/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.1.111/linux/drivers/block/ide.c	Wed Jul  1 19:38:53 1998
+++ linux/drivers/block/ide.c	Sun Jul 26 11:46:46 1998
@@ -1525,6 +1525,7 @@
 			if (sb)
 				invalidate_inodes(sb);
 			invalidate_buffers (devp);
+			set_blocksize(devp, 1024);
 		}
 		drive->part[p].start_sect = 0;
 		drive->part[p].nr_sects   = 0;
diff -u --recursive --new-file v2.1.111/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.1.111/linux/drivers/char/console.c	Sun Jul 26 11:57:15 1998
+++ linux/drivers/char/console.c	Mon Jul 27 14:44:47 1998
@@ -188,7 +188,7 @@
 	return p;
 }
 
-static inline void scrolldelta(int lines)
+static void scrolldelta(int lines)
 {
 	int currcons = fg_console;
 
@@ -314,6 +314,8 @@
 		a ^= 0x80;
 	if (_intensity == 2)
 		a ^= 0x08;
+	if (hi_font_mask == 0x100)
+		a <<= 1;
 	return a;
 	}
 #else
@@ -339,17 +341,23 @@
 		sw->con_invert_region(vc_cons[currcons].d, p, count);
 #ifndef VT_BUF_VRAM_ONLY
 	else {
-		int col = can_do_color;
 		u16 *q = p;
 		int cnt = count;
 
-		while (cnt--) {
-			u16 a = *q;
-			if (col)
+		if (!can_do_color) {
+			while (cnt--) *q++ ^= 0x0800;
+		} else if (hi_font_mask == 0x100) {
+			while (cnt--) {
+				u16 a = *q;
+				a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
+				*q++ = a;
+			}
+		} else {
+			while (cnt--) {
+				u16 a = *q;
 				a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
-			else
-				a ^= 0x0800;
-			*q++ = a;
+				*q++ = a;
+			}
 		}
 	}
 #endif
@@ -436,9 +444,9 @@
 	int i = scr_readw((u16 *) pos);
 	u32 type = cursor_type;
 
+	if (! (type & 0x10)) return;
 	if (softcursor_original != -1) return;
 	softcursor_original = i;
-	if (! (type & 0x10)) return;
 	i |= ((type >> 8) & 0xff00 );
 	i ^= ((type) & 0xff00 );
 	if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
@@ -450,6 +458,8 @@
 
 static void hide_cursor(int currcons)
 {
+	if (currcons == sel_cons)
+		clear_selection();
 	if (softcursor_original != -1) {
 		scr_writew(softcursor_original,(u16 *) pos);
 		if (DO_UPDATE)
@@ -464,6 +474,8 @@
     if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS)
 	return;
     if (deccm) {
+	if (currcons == sel_cons)
+		clear_selection();
 	add_softcursor(currcons);
 	if ((cursor_type & 0x0f) != 1)
 	    sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
@@ -510,8 +522,6 @@
 	}
 	lock = 1;
 
-	clear_selection();
-
 	hide_cursor(currcons);
 	if (fg_console != new_console) {
 		display = vc_cons[new_console].d->vc_display_fg;
@@ -552,6 +562,8 @@
     sw = conswitchp;
     cons_num = currcons;
     display_fg = &master_display_fg;
+    vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir;
+    vc_cons[currcons].d->vc_uni_pagedir = 0;
     hi_font_mask = 0;
     complement_mask = 0;
     sw->con_init(vc_cons[currcons].d, 1);
@@ -591,6 +603,7 @@
 		vt_cons[currcons] = NULL;
 		return -ENOMEM;
 	    }
+	    con_set_default_unimap(currcons);
 	    screenbuf = (unsigned short *) q;
 	    kmalloced = 1;
 	    screenbuf_size = video_screen_size;
@@ -1667,14 +1680,10 @@
 			/* DEC screen alignment test. kludge :-) */
 			video_erase_char =
 				(video_erase_char & 0xff00) | 'E';
-			/* Arno:
-			 * Doesn't work, because csi_J(c,2)
-			 * calls con_clear and doesn't print
-			 * the erase char..	FIXME
-			 */
 			csi_J(currcons, 2);
 			video_erase_char =
 				(video_erase_char & 0xff00) | ' ';
+			do_update_region(currcons, origin, screenbuf_size/2);
 		}
 		return;
 	case ESsetG0:
@@ -1755,10 +1764,6 @@
 	if (IS_FG)
 		hide_cursor(currcons);
 
-	/* clear the selection */
-	if (currcons == sel_cons)
-		clear_selection();
-
 	disable_bh(CONSOLE_BH);
 	while (!tty->stopped && count) {
 		enable_bh(CONSOLE_BH);
@@ -1825,11 +1830,11 @@
 
 		if (vc_state == ESnormal && ok) {
 			/* Now try to find out how to display it */
-			tc = conv_uni_to_pc(tc);
+			tc = conv_uni_to_pc(vc_cons[currcons].d, tc);
 			if ( tc == -4 ) {
                                 /* If we got -4 (not found) then see if we have
                                    defined a replacement character (U+FFFD) */
-                                tc = conv_uni_to_pc(0xfffd);
+                                tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd);
 
 				/* One reason for the -4 can be that we just
 				   did a clear_unimap();
@@ -1889,8 +1894,7 @@
 static void console_bh(void)
 {
 	if (want_console >= 0) {
-		if (want_console != fg_console) {
-			clear_selection();
+		if (want_console != fg_console && vc_cons_allocated(want_console)) {
 			hide_cursor(fg_console);
 			save_screen();
 			change_console(want_console);
@@ -2401,8 +2405,8 @@
 
 	/* entering graphics mode? */
 	if (nopowersave) {
-		save_screen();
 		hide_cursor(currcons);
+		save_screen();
 		sw->con_blank(vc_cons[currcons].d, -1);
 		console_blanked = fg_console + 1;
 		set_origin(currcons);
@@ -2460,6 +2464,9 @@
 
 	currcons = fg_console;
 	console_blanked = 0;
+#ifdef CONFIG_APM
+	apm_display_unblank();
+#endif
 	if (sw->con_blank(vc_cons[currcons].d, 0))
 		/* Low-level driver cannot restore -> do it ourselves */
 		update_screen(fg_console);
@@ -2567,24 +2574,31 @@
  *  /Jes
  */
 
-#define max_font_size 32768
+#define max_font_size 65536
 
 int con_font_op(int currcons, struct console_font_op *op)
 {
 	int rc = -EINVAL;
-	int size, set;
-	u8 *temp;
+	int size = max_font_size, set;
+	u8 *temp = NULL;
 	struct console_font_op old_op;
 
 	if (vt_cons[currcons]->vc_mode != KD_TEXT)
 		goto quit;
-	memcpy(&old_op, &op, sizeof(op));
+	memcpy(&old_op, op, sizeof(old_op));
 	if (op->op == KD_FONT_OP_SET) {
+		if (!op->data)
+			return -EINVAL;
 		if (op->charcount > 512)
 			goto quit;
 		if (!op->height) {		/* Need to guess font height [compat] */
 			int h, i;
 			u8 *charmap = op->data, tmp;
+			
+			/* If from KDFONTOP ioctl, don't allow things which can be done in userland,
+			   so that we can get rid of this soon */
+			if (op->flags & KD_FONT_FLAG_NEW)
+				goto quit;
 			rc = -EFAULT;
 			for (h = 32; h > 0; h--)
 				for (i = 0; i < op->charcount; i++) {
@@ -2605,32 +2619,44 @@
 		if (size > max_font_size)
 			return -ENOSPC;
 		set = 1;
-	} else if (op->op == KD_FONT_OP_GET) {
-		size = max_font_size;
+	} else if (op->op == KD_FONT_OP_GET)
 		set = 0;
-	} else
+	else
 		return sw->con_font_op(vc_cons[currcons].d, op);
-	temp = kmalloc(size, GFP_KERNEL);
-	if (!temp)
-		return -ENOMEM;
-	if (set && copy_from_user(temp, op->data, size)) {
-		rc = -EFAULT;
-		goto quit2;
+	if (op->data) {
+		temp = kmalloc(size, GFP_KERNEL);
+		if (!temp)
+			return -ENOMEM;
+		if (set && copy_from_user(temp, op->data, size)) {
+			rc = -EFAULT;
+			goto quit;
+		}
+		op->data = temp;
 	}
-	op->data = temp;
 	rc = sw->con_font_op(vc_cons[currcons].d, op);
 	op->data = old_op.data;
 	if (!rc && !set) {
 		int c = (op->width+7)/8 * 32 * op->charcount;
-		if (op->width > old_op.width ||
-		    op->height > old_op.height ||
-		    op->charcount > old_op.charcount)
+		
+		if (op->data && op->charcount > old_op.charcount)
 			rc = -ENOSPC;
-		else if (copy_to_user(old_op.data, op->data, c))
+		if (op->flags & KD_FONT_FLAG_NEW) {
+			if (op->width > old_op.width || 
+			    op->height > old_op.height)
+				rc = -ENOSPC;
+		} else {
+			if (op->width != 8)
+				rc = -EIO;
+			else if ((old_op.height && op->height > old_op.height) ||
+			         op->height > 32)
+				rc = -ENOSPC;
+		}
+		if (!rc && op->data && copy_to_user(op->data, temp, c))
 			rc = -EFAULT;
 	}
-quit2:	kfree_s(temp, size);
-quit:	return rc;
+quit:	if (temp)
+		kfree_s(temp, size);
+	return rc;
 }
 
 /*
@@ -2664,6 +2690,22 @@
 {
 	gotoxy(currcons, p[0], p[1]);
 	set_cursor(currcons);
+}
+
+u16 vcs_scr_readw(int currcons, u16 *org)
+{
+	if (org == (u16 *)pos && softcursor_original != -1)
+		return softcursor_original;
+	return scr_readw(org);
+}
+
+void vcs_scr_writew(int currcons, u16 val, u16 *org)
+{
+	scr_writew(val, org);
+	if (org == (u16 *)pos) {
+		softcursor_original = -1;
+		add_softcursor(currcons);
+	}
 }
 
 
diff -u --recursive --new-file v2.1.111/linux/drivers/char/consolemap.c linux/drivers/char/consolemap.c
--- v2.1.111/linux/drivers/char/consolemap.c	Mon Aug 11 17:28:19 1997
+++ linux/drivers/char/consolemap.c	Sun Jul 26 14:40:18 1998
@@ -5,6 +5,8 @@
  * to font positions.
  *
  * aeb, 950210
+ *
+ * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998
  */
 
 #include <linux/kd.h>
@@ -14,6 +16,8 @@
 #include <linux/init.h>
 #include <asm/uaccess.h>
 #include <linux/consolemap.h>
+#include <linux/console_struct.h>
+#include <linux/vt_kern.h>
 
 static unsigned short translations[][256] = {
   /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
@@ -163,29 +167,36 @@
 
 #define MAX_GLYPH 512		/* Max possible glyph value */
 
-static unsigned char * inv_translate = NULL;
-static unsigned char inv_norm_transl[MAX_GLYPH];
-static unsigned char * inverse_translations[4] = { NULL, NULL, NULL, NULL };
+static int inv_translate;
+
+struct uni_pagedir {
+	u16 		**uni_pgdir[32];
+	unsigned long	refcount;
+	unsigned long	sum;
+	unsigned char	*inverse_translations[4];
+	int		readonly;
+};
 
-static void set_inverse_transl(int i)
+static struct uni_pagedir *dflt;
+
+static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i)
 {
 	int j, glyph;
-	unsigned short *p = translations[i];
-	unsigned char *q = inverse_translations[i];
+	unsigned short *t = translations[i];
+	unsigned char *q;
+	
+	if (!p) return;
+	q = p->inverse_translations[i];
 
 	if (!q) {
-		/* slightly messy to avoid calling kmalloc too early */
-		q = inverse_translations[i] = ((i == LAT1_MAP)
-			? inv_norm_transl
-			: (unsigned char *) kmalloc(MAX_GLYPH, GFP_KERNEL));
-		if (!q)
-			return;
+		q = p->inverse_translations[i] = (unsigned char *) 
+			kmalloc(MAX_GLYPH, GFP_KERNEL);
+		if (!q) return;
 	}
-	for (j=0; j<MAX_GLYPH; j++)
-		q[j] = 0;
+	memset(q, 0, MAX_GLYPH);
 
-	for (j=0; j<E_TABSZ; j++) {
-		glyph = conv_uni_to_pc(p[j]);
+	for (j = 0; j < E_TABSZ; j++) {
+		glyph = conv_uni_to_pc(conp, t[j]);
 		if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) {
 			/* prefer '-' above SHY etc. */
 		  	q[glyph] = j;
@@ -195,9 +206,7 @@
 
 unsigned short *set_translate(int m)
 {
-	if (!inverse_translations[m])
-		set_inverse_transl(m);
-	inv_translate = inverse_translations[m];
+	inv_translate = m;
 	return translations[m];
 }
 
@@ -208,13 +217,33 @@
  *    was active, or using Unicode.
  * Still, it is now possible to a certain extent to cut and paste non-ASCII.
  */
-unsigned char inverse_translate(int glyph) {
-	if ( glyph < 0 || glyph >= MAX_GLYPH )
+unsigned char inverse_translate(struct vc_data *conp, int glyph)
+{
+	struct uni_pagedir *p;
+	
+	if (glyph < 0 || glyph >= MAX_GLYPH)
 		return 0;
+	else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc) ||
+		 !p->inverse_translations[inv_translate])
+		return glyph;
 	else
-		return ((inv_translate && inv_translate[glyph])
-			? inv_translate[glyph]
-			: (unsigned char)(glyph & 0xff));
+		return p->inverse_translations[inv_translate][glyph];
+}
+
+static void update_user_maps(void)
+{
+	int i;
+	struct uni_pagedir *p, *q = NULL;
+	
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		if (!vc_cons_allocated(i))
+			continue;
+		p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+		if (p && p != q) {
+			set_inverse_transl(vc_cons[i].d, p, USER_MAP);
+			q = p;
+		}
+	}
 }
 
 /*
@@ -240,7 +269,7 @@
 		p[i] = UNI_DIRECT_BASE | uc;
 	}
 
-	set_inverse_transl(USER_MAP);
+	update_user_maps();
 	return 0;
 }
 
@@ -255,7 +284,7 @@
 
 	for (i=0; i<E_TABSZ ; i++)
 	  {
-	    ch = conv_uni_to_pc(p[i]);
+	    ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
 	    __put_user((ch & ~0xff) ? 0 : ch, arg+i);
 	  }
 	return 0;
@@ -277,7 +306,7 @@
 		p[i] = us;
 	}
 
-	set_inverse_transl(USER_MAP);
+	update_user_maps();
 	return 0;
 }
 
@@ -310,90 +339,188 @@
 extern u8 dfont_unicount[];	/* Defined in console_defmap.c */
 extern u16 dfont_unitable[];
 
-int hashtable_contents_valid = 0; /* Use ASCII-only mode for bootup */
+static void con_release_unimap(struct uni_pagedir *p)
+{
+	u16 **p1;
+	int i, j;
 
-static u16 **uni_pagedir[32] =
+	if (p == dflt) dflt = NULL;  
+	for (i = 0; i < 32; i++) {
+		if ((p1 = p->uni_pgdir[i]) != NULL) {
+			for (j = 0; j < 32; j++)
+				if (p1[j])
+					kfree(p1[j]);
+			kfree(p1);
+		}
+		p->uni_pgdir[i] = NULL;
+	}
+	for (i = 0; i < 4; i++)
+		if (p->inverse_translations[i]) {
+			kfree(p->inverse_translations[i]);
+			p->inverse_translations[i] = NULL;
+		}
+}
+
+void con_free_unimap(int con)
 {
-  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
-};
+	struct uni_pagedir *p;
+	struct vc_data *conp = vc_cons[con].d;
+	
+	p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+	if (!p) return;
+	*conp->vc_uni_pagedir_loc = 0;
+	if (--p->refcount) return;
+	con_release_unimap(p);
+	kfree(p);
+}
+  
+static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
+{
+	int i, j, k;
+	struct uni_pagedir *q;
+	
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		if (!vc_cons_allocated(i))
+			continue;
+		q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+		if (!q || q == p || q->sum != p->sum)
+			continue;
+		for (j = 0; j < 32; j++) {
+			u16 **p1, **q1;
+			p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
+			if (!p1 && !q1)
+				continue;
+			if (!p1 || !q1)
+				break;
+			for (k = 0; k < 32; k++) {
+				if (!p1[k] && !q1[k])
+					continue;
+				if (!p1[k] || !q1[k])
+					break;
+				if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
+					break;
+			}
+			if (k < 32)
+				break;
+		}
+		if (j == 32) {
+			q->refcount++;
+			*conp->vc_uni_pagedir_loc = (unsigned long)q;
+			con_release_unimap(p);
+			kfree(p);
+			return 1;
+		}
+	}
+	return 0;
+}
 
 static int
-con_insert_unipair(u_short unicode, u_short fontpos)
+con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
 {
-  int i, n;
-  u16 **p1, *p2;
+	int i, n;
+	u16 **p1, *p2;
 
-  if ( !(p1 = uni_pagedir[n = unicode >> 11]) )
-    {
-      p1 = uni_pagedir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
-      if ( !p1 )
-	return -ENOMEM;
-
-      for ( i = 0 ; i < 32 ; i++ )
-	p1[i] = NULL;
-    }
-
-  if ( !(p2 = p1[n = (unicode >> 6) & 0x1f]) )
-    {
-      p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
-      if ( !p2 )
-	return -ENOMEM;
-
-      for ( i = 0 ; i < 64 ; i++ )
-	p2[i] = 0xffff;		/* No glyph for this character (yet) */
-    }
+	if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
+		p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
+		if (!p1) return -ENOMEM;
+		for (i = 0; i < 32; i++)
+			p1[i] = NULL;
+	}
 
-  p2[unicode & 0x3f] = fontpos;
-  
-  return 0;
+	if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
+		p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
+		if (!p2) return -ENOMEM;
+		memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
+	}
+
+	p2[unicode & 0x3f] = fontpos;
+	
+	p->sum += (fontpos << 20) + unicode;
+
+	return 0;
 }
-  
+
 /* ui is a leftover from using a hashtable, but might be used again */
-void
-con_clear_unimap(struct unimapinit *ui)
+int con_clear_unimap(int con, struct unimapinit *ui)
 {
-  int i, j;
-  u16 **p1;
+	struct uni_pagedir *p, *q;
+	struct vc_data *conp = vc_cons[con].d;
   
-  for ( i = 0 ; i < 32 ; i++ )
-    {
-      if ( (p1 = uni_pagedir[i]) != NULL )
-	{
-	  for ( j = 0 ; j < 32 ; j++ )
-	    {
-	      if ( p1[j] )
-		kfree(p1[j]);
-	    }
-	  kfree(p1);
+	p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+	if (p && p->readonly) return -EIO;
+	if (!p || --p->refcount) {
+		q = (struct uni_pagedir *)kmalloc(sizeof(*p), GFP_KERNEL);
+		if (!q) {
+			if (p) p->refcount++;
+			return -ENOMEM;
+		}
+		memset(q, 0, sizeof(*q));
+		q->refcount=1;
+		*conp->vc_uni_pagedir_loc = (unsigned long)q;
+	} else {
+		if (p == dflt) dflt = NULL;
+		p->refcount++;
+		p->sum = 0;
+		con_release_unimap(p);
 	}
-      uni_pagedir[i] = NULL;
-    }
-
-  hashtable_contents_valid = 1;
+	return 0;
 }
 
 int
-con_set_unimap(ushort ct, struct unipair *list)
+con_set_unimap(int con, ushort ct, struct unipair *list)
 {
-  int err = 0, err1, i;
+	int err = 0, err1, i;
+	struct uni_pagedir *p, *q;
+	struct vc_data *conp = vc_cons[con].d;
 
-  while( ct-- )
-    {
-      unsigned short unicode, fontpos;
-      __get_user(unicode, &list->unicode);
-      __get_user(fontpos, &list->fontpos);
-      if ( (err1 = con_insert_unipair(unicode,fontpos)) != 0 )
-	err = err1;
-      list++;
-    }
+	p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+	if (p->readonly) return -EIO;
+	
+	if (!ct) return 0;
+	
+	if (p->refcount > 1) {
+		int j, k;
+		u16 **p1, *p2, l;
+		
+		err1 = con_clear_unimap(con, NULL);
+		if (err1) return err1;
+		
+		q = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+		for (i = 0, l = 0; i < 32; i++)
+		if ((p1 = p->uni_pgdir[i]))
+			for (j = 0; j < 32; j++)
+			if ((p2 = p1[j]))
+				for (k = 0; k < 64; k++, l++)
+				if (p2[k] != 0xffff) {
+					err1 = con_insert_unipair(q, l, p2[k]);
+					if (err1) {
+						p->refcount++;
+						*conp->vc_uni_pagedir_loc = (unsigned long)p;
+						con_release_unimap(q);
+						kfree(q);
+						return err1; 
+					}
+              			}
+              	p = q;
+	} else if (p == dflt)
+		dflt = NULL;
+	
+	while (ct--) {
+		unsigned short unicode, fontpos;
+		__get_user(unicode, &list->unicode);
+		__get_user(fontpos, &list->fontpos);
+		if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
+			err = err1;
+			list++;
+	}
+	
+	if (con_unify_unimap(conp, p))
+		return err;
 
-  for ( i = 0 ; i <= 3 ; i++ )
-    set_inverse_transl(i); /* Update all inverse translations */
+	for (i = 0; i <= 3; i++)
+		set_inverse_transl(conp, p, i); /* Update all inverse translations */
   
-  return err;
+	return err;
 }
 
 /* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
@@ -401,83 +528,123 @@
    with.  This routine is executed at sys_setup time, and when the
    PIO_FONTRESET ioctl is called. */
 
-void
-con_set_default_unimap(void)
+int
+con_set_default_unimap(int con)
 {
-  int i, j;
-  u16 *p;
-
-  /* The default font is always 256 characters */
-
-  con_clear_unimap(NULL);
+	int i, j, err = 0, err1;
+	u16 *q;
+	struct uni_pagedir *p;
+	struct vc_data *conp = vc_cons[con].d;
+	
+	if (dflt) {
+		p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+		if (p == dflt)
+			return 0;
+		dflt->refcount++;
+		*conp->vc_uni_pagedir_loc = (unsigned long)dflt;
+		if (p && --p->refcount) {
+			con_release_unimap(p);
+			kfree(p);
+		}
+		return 0;
+	}
+	
+	/* The default font is always 256 characters */
 
-  p = dfont_unitable;
-  for ( i = 0 ; i < 256 ; i++ )
-    for ( j = dfont_unicount[i] ; j ; j-- )
-      con_insert_unipair(*(p++), i);
+	err = con_clear_unimap(con,NULL);
+	if (err) return err;
+    
+	p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+	q = dfont_unitable;
+	
+	for (i = 0; i < 256; i++)
+		for (j = dfont_unicount[i]; j; j--) {
+			err1 = con_insert_unipair(p, *(q++), i);
+			if (err1)
+				err = err1;
+		}
+			
+	if (con_unify_unimap(conp, p)) {
+		dflt = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+		return err;
+	}
 
-  for ( i = 0 ; i <= 3 ; i++ )
-    set_inverse_transl(i);	/* Update all inverse translations */
+	for (i = 0; i <= 3; i++)
+		set_inverse_transl(conp, p, i);	/* Update all inverse translations */
+	dflt = p;
+	return err;
 }
 
 int
-con_get_unimap(ushort ct, ushort *uct, struct unipair *list){
+con_get_unimap(int con, ushort ct, ushort *uct, struct unipair *list)
+{
 	int i, j, k, ect;
 	u16 **p1, *p2;
+	struct uni_pagedir *p;
+	struct vc_data *conp = vc_cons[con].d;
 
 	ect = 0;
-	if (hashtable_contents_valid)
-	  {
-	    for ( i = 0 ; i < 32 ; i++ )
-	      if ( (p1 = uni_pagedir[i]) != NULL )
-		for ( j = 0 ; j < 32 ; j++ )
-		  if ( (p2 = *(p1++)) != NULL )
-		    for ( k = 0 ; k < 64 ; k++ )
-		      {
-			if ( *p2 < MAX_GLYPH && ect++ < ct )
-			  {
-			    __put_user((u_short)((i<<11)+(j<<6)+k),
-				     &list->unicode);
-			    __put_user((u_short) *p2, &list->fontpos);
-			    list++;
-			  }
-			p2++;
-		      }
-	  }
+	if (*conp->vc_uni_pagedir_loc) {
+		p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+		for (i = 0; i < 32; i++)
+		if ((p1 = p->uni_pgdir[i]))
+			for (j = 0; j < 32; j++)
+			if ((p2 = *(p1++)))
+				for (k = 0; k < 64; k++) {
+					if (*p2 < MAX_GLYPH && ect++ < ct) {
+						__put_user((u_short)((i<<11)+(j<<6)+k),
+							   &list->unicode);
+						__put_user((u_short) *p2, 
+							   &list->fontpos);
+						list++;
+					}
+					p2++;
+				}
+	}
 	__put_user(ect, uct);
 	return ((ect <= ct) ? 0 : -ENOMEM);
 }
 
+void con_protect_unimap(int con, int rdonly)
+{
+	struct uni_pagedir *p = (struct uni_pagedir *)
+		*vc_cons[con].d->vc_uni_pagedir_loc;
+	
+	if (p) p->readonly = rdonly;
+}
+
 int
-conv_uni_to_pc(long ucs) 
+conv_uni_to_pc(struct vc_data *conp, long ucs) 
 {
-  int h;
-  u16 **p1, *p2;
-  
-  /* Only 16-bit codes supported at this time */
-  if (ucs > 0xffff)
-    ucs = 0xfffd;		/* U+FFFD: REPLACEMENT CHARACTER */
-  else if (ucs < 0x20 || ucs >= 0xfffe)
-    return -1;		/* Not a printable character */
-  else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
-    return -2;			/* Zero-width space */
-  /*
-   * UNI_DIRECT_BASE indicates the start of the region in the User Zone
-   * which always has a 1:1 mapping to the currently loaded font.  The
-   * UNI_DIRECT_MASK indicates the bit span of the region.
-   */
-  else if ( (ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE )
-    return ucs & UNI_DIRECT_MASK;
+	int h;
+	u16 **p1, *p2;
+	struct uni_pagedir *p;
   
-  if (!hashtable_contents_valid)
-    return -3;
+	/* Only 16-bit codes supported at this time */
+	if (ucs > 0xffff)
+		ucs = 0xfffd;		/* U+FFFD: REPLACEMENT CHARACTER */
+	else if (ucs < 0x20 || ucs >= 0xfffe)
+		return -1;		/* Not a printable character */
+	else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
+		return -2;			/* Zero-width space */
+	/*
+	 * UNI_DIRECT_BASE indicates the start of the region in the User Zone
+	 * which always has a 1:1 mapping to the currently loaded font.  The
+	 * UNI_DIRECT_MASK indicates the bit span of the region.
+	 */
+	else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
+		return ucs & UNI_DIRECT_MASK;
   
-  if ( (p1 = uni_pagedir[ucs >> 11]) &&
-      (p2 = p1[(ucs >> 6) & 0x1f]) &&
-      (h = p2[ucs & 0x3f]) < MAX_GLYPH )
-    return h;
+	if (!*conp->vc_uni_pagedir_loc)
+		return -3;
+
+	p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;  
+	if ((p1 = p->uni_pgdir[ucs >> 11]) &&
+	    (p2 = p1[(ucs >> 6) & 0x1f]) &&
+	    (h = p2[ucs & 0x3f]) < MAX_GLYPH)
+		return h;
 
-  return -4;		/* not found */
+	return -4;		/* not found */
 }
 
 /*
@@ -488,5 +655,9 @@
 __initfunc(void
 console_map_init(void))
 {
-  con_set_default_unimap();
+	int i;
+	
+	for (i = 0; i < MAX_NR_CONSOLES; i++)
+		if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
+			con_set_default_unimap(i);
 }
diff -u --recursive --new-file v2.1.111/linux/drivers/char/esp.c linux/drivers/char/esp.c
--- v2.1.111/linux/drivers/char/esp.c	Sun Jul 26 11:57:15 1998
+++ linux/drivers/char/esp.c	Sat Jul 25 18:48:29 1998
@@ -37,7 +37,6 @@
  *	int espserial_init(void);
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
diff -u --recursive --new-file v2.1.111/linux/drivers/char/fbmem.c linux/drivers/char/fbmem.c
--- v2.1.111/linux/drivers/char/fbmem.c	Tue Jul 21 00:15:31 1998
+++ linux/drivers/char/fbmem.c	Mon Jul 27 13:59:28 1998
@@ -420,6 +420,9 @@
 #elif defined(__sparc__)
 	/* Should never get here, all fb drivers should have their own
 	   mmap routines */
+#elif defined(__i386__)
+	if (boot_cpu_data.x86 > 3)
+		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
 #else
 #warning What do we have to do here??
 #endif
diff -u --recursive --new-file v2.1.111/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c
--- v2.1.111/linux/drivers/char/msp3400.c	Sun Jul 26 11:57:15 1998
+++ linux/drivers/char/msp3400.c	Mon Jul 27 18:27:54 1998
@@ -37,7 +37,6 @@
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/malloc.h>
-/* #include <asm/smp_lock.h> */
 
 /* kernel_thread */
 #define __KERNEL_SYSCALLS__
diff -u --recursive --new-file v2.1.111/linux/drivers/char/selection.c linux/drivers/char/selection.c
--- v2.1.111/linux/drivers/char/selection.c	Sun Jul 26 11:57:15 1998
+++ linux/drivers/char/selection.c	Sun Jul 26 14:40:18 1998
@@ -60,7 +60,7 @@
 static unsigned char
 sel_pos(int n)
 {
-	return inverse_translate(screen_glyph(sel_cons, n));
+	return inverse_translate(vc_cons[sel_cons].d, screen_glyph(sel_cons, n));
 }
 
 /* remove the current selection highlight, if any,
diff -u --recursive --new-file v2.1.111/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c
--- v2.1.111/linux/drivers/char/sysrq.c	Fri May  8 23:14:47 1998
+++ linux/drivers/char/sysrq.c	Mon Jul 27 18:21:33 1998
@@ -20,8 +20,9 @@
 #include <linux/sysrq.h>
 #include <linux/kbd_kern.h>
 #include <linux/quotaops.h>
+#include <linux/smp_lock.h>
+
 #include <asm/ptrace.h>
-#include <asm/smp_lock.h>
 
 #ifdef CONFIG_APM
 #include <linux/apm_bios.h>
diff -u --recursive --new-file v2.1.111/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c
--- v2.1.111/linux/drivers/char/vc_screen.c	Sun Jul 26 11:57:15 1998
+++ linux/drivers/char/vc_screen.c	Sun Jul 26 14:40:18 1998
@@ -7,7 +7,8 @@
  *            [minor: N]
  *
  * /dev/vcsaN: idem, but including attributes, and prefixed with
- *	the 4 bytes lines,columns,x,y (as screendump used to give)
+ *	the 4 bytes lines,columns,x,y (as screendump used to give).
+ *	Attribute/character pair is in native endianity.
  *            [minor: N+128]
  *
  * This replaces screendump and part of selection, so that the system
@@ -20,6 +21,8 @@
  *	 - making it shorter - scr_readw are macros which expand in PRETTY long code
  */
 
+#include <linux/config.h>
+
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/errno.h>
@@ -39,18 +42,6 @@
 #undef addr
 #define HEADER_SIZE	4
 
-static unsigned short
-func_scr_readw(unsigned short *org)
-{
-return scr_readw( org );
-}
-
-static void
-func_scr_writew(unsigned short val, unsigned short *org)
-{
-scr_writew( val, org );
-}
-
 static int
 vcs_size(struct inode *inode)
 {
@@ -91,7 +82,7 @@
 	return file->f_pos;
 }
 
-#define RETURN( x ) { enable_bh( CONSOLE_BH ); return x; }
+#define RETURN(x) { enable_bh(CONSOLE_BH); return x; }
 static ssize_t
 vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 {
@@ -104,7 +95,7 @@
 
 	attr = (currcons & 128);
 	currcons = (currcons & 127);
-	disable_bh( CONSOLE_BH );
+	disable_bh(CONSOLE_BH);
 	if (currcons == 0) {
 		currcons = fg_console;
 		viewed = 1;
@@ -125,7 +116,7 @@
 	if (!attr) {
 		org = screen_pos(currcons, p, viewed);
 		while (count-- > 0)
-			put_user(func_scr_readw(org++) & 0xff, buf++);
+			put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++);
 	} else {
 		if (p < HEADER_SIZE) {
 			char header[HEADER_SIZE];
@@ -140,21 +131,21 @@
 		    org = screen_pos(currcons, p/2, viewed);
 		    if ((p & 1) && count > 0)
 #ifdef __BIG_ENDIAN
-			    { count--; put_user(func_scr_readw(org++) & 0xff, buf++); }
+			    { count--; put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++); }
 #else
-			    { count--; put_user(func_scr_readw(org++) >> 8, buf++); }
+			    { count--; put_user(vcs_scr_readw(currcons, org++) >> 8, buf++); }
 #endif
 		}
 		while (count > 1) {
-			put_user(func_scr_readw(org++), (unsigned short *) buf);
+			put_user(vcs_scr_readw(currcons, org++), (unsigned short *) buf);
 			buf += 2;
 			count -= 2;
 		}
 		if (count > 0)
 #ifdef __BIG_ENDIAN
-			put_user(func_scr_readw(org) >> 8, buf++);
+			put_user(vcs_scr_readw(currcons, org) >> 8, buf++);
 #else
-			put_user(func_scr_readw(org) & 0xff, buf++);
+			put_user(vcs_scr_readw(currcons, org) & 0xff, buf++);
 #endif
 	}
 	read = buf - buf0;
@@ -174,7 +165,7 @@
 
 	attr = (currcons & 128);
 	currcons = (currcons & 127);
-	disable_bh( CONSOLE_BH );
+	disable_bh(CONSOLE_BH);
 	if (currcons == 0) {
 		currcons = fg_console;
 		viewed = 1;
@@ -198,7 +189,7 @@
 			unsigned char c;
 			count--;
 			get_user(c, (const unsigned char*)buf++);
-			func_scr_writew((func_scr_readw(org) & 0xff00) | c, org);
+			vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org);
 			org++;
 		}
 	} else {
@@ -218,11 +209,11 @@
 				count--;
 				get_user(c,buf++);
 #ifdef __BIG_ENDIAN
-				func_scr_writew(c |
-				     (func_scr_readw(org) & 0xff00), org);
+				vcs_scr_writew(currcons, c |
+				     (vcs_scr_readw(currcons, org) & 0xff00), org);
 #else
-				func_scr_writew((c << 8) |
-				     (func_scr_readw(org) & 0xff), org);
+				vcs_scr_writew(currcons, (c << 8) |
+				     (vcs_scr_readw(currcons, org) & 0xff), org);
 #endif
 				org++;
 			}
@@ -230,7 +221,7 @@
 		while (count > 1) {
 			unsigned short w;
 			get_user(w, (const unsigned short *) buf);
-			func_scr_writew(w, org++);
+			vcs_scr_writew(currcons, w, org++);
 			buf += 2;
 			count -= 2;
 		}
@@ -238,9 +229,9 @@
 			unsigned char c;
 			get_user(c, (const unsigned char*)buf++);
 #ifdef __BIG_ENDIAN
-			func_scr_writew((func_scr_readw(org) & 0xff) | (c << 8), org);
+			vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff) | (c << 8), org);
 #else
-			func_scr_writew((func_scr_readw(org) & 0xff00) | c, org);
+			vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org);
 #endif
 		}
 	}
diff -u --recursive --new-file v2.1.111/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v2.1.111/linux/drivers/char/vt.c	Sun Jul 26 11:57:15 1998
+++ linux/drivers/char/vt.c	Sun Jul 26 14:40:18 1998
@@ -113,21 +113,18 @@
 }
 
 /*
- * Generates sound of some count for some number of clock ticks
- * [count = 1193180 / frequency]
+ * Generates sound of some frequency for some number of clock ticks
  *
  * If freq is 0, will turn off sound, else will turn it on for that time.
  * If msec is 0, will return immediately, else will sleep for msec time, then
  * turn sound off.
  *
- * We use the BEEP_TIMER vector since we're using the same method to
- * generate sound, and we'll overwrite any beep in progress. That may
- * be something to fix later, if we like.
- *
  * We also return immediately, which is what was implied within the X
  * comments - KDMKTONE doesn't put the process to sleep.
  */
-/* FIXME: This should go to arch-dependent code */
+
+#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) || defined(__mips__)
+
 static void
 kd_nosound(unsigned long ignored)
 {
@@ -168,6 +165,15 @@
 	return;
 }
 
+#else
+
+void
+_kd_mksound(unsigned int hz, unsigned int ticks)
+{
+}
+
+#endif
+
 void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound;
 
 
@@ -394,8 +400,6 @@
 		op.data = cfdarg.chardata;
 		return con_font_op(fg_console, &op);
 	case GIO_FONTX: {
-		if (!cfdarg.chardata)
-			return 0;
 		op.op = KD_FONT_OP_GET;
 		op.flags = 0;
 		op.width = 8;
@@ -432,9 +436,9 @@
 	case PIO_UNIMAP:
 		if (!perm)
 			return -EPERM;
-		return con_set_unimap(tmp.entry_ct, tmp.entries);
+		return con_set_unimap(fg_console, tmp.entry_ct, tmp.entries);
 	case GIO_UNIMAP:
-		return con_get_unimap(tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
+		return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
 	}
 	return 0;
 }
@@ -994,11 +998,11 @@
 #else
 		{
 		struct console_font_op op;
-		op.op = KD_FONT_SET_DEFAULT;
+		op.op = KD_FONT_OP_SET_DEFAULT;
 		op.data = NULL;
 		i = con_font_op(fg_console, &op);
 		if (i) return i;
-		con_set_default_unimap();
+		con_set_default_unimap(fg_console);
 		return 0;
 		}
 #endif
@@ -1010,6 +1014,7 @@
 			return -EFAULT;
 		if (!perm && op.op != KD_FONT_OP_GET)
 			return -EPERM;
+		op.flags |= KD_FONT_FLAG_NEW;
 		i = con_font_op(console, &op);
 		if (i) return i;
 		if (copy_to_user((void *) arg, &op, sizeof(op)))
@@ -1039,7 +1044,7 @@
 			return -EPERM;
 		i = copy_from_user(&ui, (void *)arg, sizeof(struct unimapinit));
 		if (i) return -EFAULT;
-		con_clear_unimap(&ui);
+		con_clear_unimap(fg_console, &ui);
 		return 0;
 	      }
 
@@ -1189,10 +1194,6 @@
 {
 	unsigned char old_vc_mode;
 
-        if ((new_console == fg_console) || (vt_dont_switch))
-                return;
-        if (!vc_cons_allocated(new_console))
-                return;
 	last_console = fg_console;
 
 	/*
diff -u --recursive --new-file v2.1.111/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c
--- v2.1.111/linux/drivers/misc/parport_procfs.c	Tue Jul 21 00:15:31 1998
+++ linux/drivers/misc/parport_procfs.c	Sun Jul 26 19:39:25 1998
@@ -182,6 +182,8 @@
 	int len = 0;
 	const char *str;
 
+	page[0] = '\0';
+
 	if ((str = pp->probe_info.class_name) != NULL)
 		len += sprintf (page+len, "CLASS:%s;\n", str);
 
@@ -199,7 +201,7 @@
 
 	*start = 0;
 	*eof   = 1;
-	return strlen (page);
+	return len;
 }
 
 static inline void destroy_proc_entry(struct proc_dir_entry *root, 
diff -u --recursive --new-file v2.1.111/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.1.111/linux/drivers/net/3c509.c	Sun Jul 26 11:57:15 1998
+++ linux/drivers/net/3c509.c	Sun Jul 26 23:35:55 1998
@@ -451,6 +451,8 @@
 		dev->tbusy = 0;
 	}
 
+	lp->stats.tx_bytes += skb->len;
+	
 	if (el3_debug > 4) {
 		printk("%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
 			   dev->name, skb->len, inw(ioaddr + EL3_STATUS));
@@ -667,6 +669,7 @@
 			struct sk_buff *skb;
 
 			skb = dev_alloc_skb(pkt_len+5);
+			lp->stats.rx_bytes += pkt_len;
 			if (el3_debug > 4)
 				printk("Receiving packet size %d status %4.4x.\n",
 					   pkt_len, rx_status);
diff -u --recursive --new-file v2.1.111/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.1.111/linux/drivers/net/Config.in	Sun Jul 26 11:57:15 1998
+++ linux/drivers/net/Config.in	Sun Jul 26 23:35:55 1998
@@ -31,8 +31,14 @@
       source drivers/acorn/net/Config.in
     fi
   fi
-  if [ "$CONFIG_PMAC" = "y" ]; then
-    bool 'MACE (Power Mac Ethernet) support' CONFIG_MACE
+  if [ "$CONFIG_PPC" = "y" ]; then
+    bool 'MACE (Power Mac ethernet) support' CONFIG_MACE
+    bool 'BMAC (G3 ethernet) support' CONFIG_BMAC
+  fi
+  if [ "$CONFIG_APUS" = "y" ]; then
+    tristate 'Ariadne support' CONFIG_ARIADNE
+    tristate 'A2065 support' CONFIG_A2065
+    tristate 'Hydra support' CONFIG_HYDRA
   fi
   if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then
     bool 'MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC
diff -u --recursive --new-file v2.1.111/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.1.111/linux/drivers/net/Makefile	Sun Jul 26 11:57:15 1998
+++ linux/drivers/net/Makefile	Sun Jul 26 23:35:56 1998
@@ -151,6 +151,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_ETHERH),y)
+CONFIG_8390_BUILTIN = y
+else
+  ifeq ($(CONFIG_ETHERH),m)
+  CONFIG_8390_MODULE = y
+  endif
+endif
+
 ifeq ($(CONFIG_NE2K_PCI),y)
 L_OBJS += ne2k-pci.o
 CONFIG_8390_BUILTIN = y
@@ -851,6 +859,10 @@
 
 ifeq ($(CONFIG_MACE),y)
 L_OBJS += mace.o
+endif
+
+ifeq ($(CONFIG_BMAC),y)
+L_OBJS += bmac.o
 endif
 
 ifeq ($(CONFIG_VENDOR_SANGOMA),y)
diff -u --recursive --new-file v2.1.111/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.1.111/linux/drivers/net/Space.c	Tue Jul 21 00:15:31 1998
+++ linux/drivers/net/Space.c	Sun Jul 26 23:35:56 1998
@@ -95,6 +95,7 @@
 extern int pamsnet_probe(struct device *);
 extern int tlan_probe(struct device *);
 extern int mace_probe(struct device *);
+extern int bmac_probe(struct device *);
 extern int cs89x0_probe(struct device *dev);
 extern int ethertap_probe(struct device *dev);
 extern int ether1_probe (struct device *dev);
@@ -380,6 +381,9 @@
 struct devprobe ppc_probes[] __initdata = {
 #ifdef CONFIG_MACE
 	{mace_probe, 0},
+#endif
+#ifdef CONFIG_BMAC
+	{bmac_probe, 0},
 #endif
 	{NULL, 0},
 };
diff -u --recursive --new-file v2.1.111/linux/drivers/net/bmac.c linux/drivers/net/bmac.c
--- v2.1.111/linux/drivers/net/bmac.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/bmac.c	Sun Jul 26 23:35:56 1998
@@ -0,0 +1,1450 @@
+/*
+ * Network device driver for the BMAC ethernet controller on
+ * Apple Powermacs.  Assumes it's under a DBDMA controller.
+ *
+ * Copyright (C) 1998 Randy Gobbel.
+ */
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/proc_fs.h>
+#include <asm/prom.h>
+#include <asm/dbdma.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include "bmac.h"
+
+#define trunc_page(x)	((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1))))
+#define round_page(x)	trunc_page(((unsigned long)(x)) + ((unsigned long)(PAGE_SIZE - 1)))
+
+/*
+ * CRC polynomial - used in working out multicast filter bits.
+ */
+#define ENET_CRCPOLY 0x04c11db7
+
+/* a bunch of constants for the "Heathrow" interrupt controller.
+   These really should be in an include file somewhere */
+#define IoBaseHeathrow ((unsigned *)0xf3000000)
+#define HeathrowFCR 0x0038	/* FCR offset from Heathrow Base Address */
+#define fcrEnetEnabledBits	0x60000000 /* mask to enable Enet Xcvr/Controller */
+#define fcrResetEnetCell	0x80000000 /* mask used to reset Enet cell */
+#define fcrClearResetEnetCell	0x7fffffff /* mask used to clear reset Enet cell */
+#define fcrDisableEnet		0x1fffffff /* mask to disable Enet Xcvr/Controller */
+
+#define N_RX_RING	64
+#define N_TX_RING	32
+#define MAX_TX_ACTIVE	1
+#define ETHERCRC	4
+#define ETHERMINPACKET	64
+#define ETHERMTU	1500
+#define RX_BUFLEN	(ETHERMTU + 14 + ETHERCRC + 2)
+#define TX_TIMEOUT	HZ	/* 1 second */
+
+/* Bits in transmit DMA status */
+#define TX_DMA_ERR	0x80
+
+#define XXDEBUG(args)
+
+struct bmac_data {
+/*     volatile struct bmac *bmac; */
+	struct sk_buff_head *queue;
+	volatile struct dbdma_regs *tx_dma;
+	int tx_dma_intr;
+	volatile struct dbdma_regs *rx_dma;
+	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 sk_buff *rx_bufs[N_RX_RING];
+	int rx_fill;
+	int rx_empty;
+	struct sk_buff *tx_bufs[N_TX_RING];
+	char *tx_double[N_TX_RING]; /* yuck--double buffering */
+	int tx_fill;
+	int tx_empty;
+	unsigned char tx_fullup;
+	struct net_device_stats stats;
+	struct timer_list tx_timeout;
+	int timeout_active;
+	int reset_and_enabled;
+	int rx_allocated;
+	int tx_allocated;
+	unsigned short hash_use_count[64];
+	unsigned short hash_table_mask[4];
+};
+
+typedef struct bmac_reg_entry {
+	char *name;
+	unsigned short reg_offset;
+} bmac_reg_entry_t;
+
+#define N_REG_ENTRIES 30
+
+bmac_reg_entry_t reg_entries[N_REG_ENTRIES] = {
+	{"MEMADD", MEMADD},
+	{"MEMDATAHI", MEMDATAHI},
+	{"MEMDATALO", MEMDATALO},
+	{"TXPNTR", TXPNTR},
+	{"RXPNTR", RXPNTR},
+	{"IPG1", IPG1},
+	{"IPG2", IPG2},
+	{"ALIMIT", ALIMIT},
+	{"SLOT", SLOT},
+	{"PALEN", PALEN},
+	{"PAPAT", PAPAT},
+	{"TXSFD", TXSFD},
+	{"JAM", JAM},
+	{"TXMAX", TXMAX},
+	{"TXMIN", TXMIN},
+	{"PAREG", PAREG},
+	{"DCNT", DCNT},
+	{"NCCNT", NCCNT},
+	{"NTCNT", NTCNT},
+	{"EXCNT", EXCNT},
+	{"LTCNT", LTCNT},
+	{"TXSM", TXSM},
+	{"RXCFG", RXCFG},
+	{"RXMAX", RXMAX},
+	{"RXMIN", RXMIN},
+	{"FRCNT", FRCNT},
+	{"AECNT", AECNT},
+	{"FECNT", FECNT},
+	{"RXSM", RXSM},
+	{"RXCV", RXCV}
+};
+
+struct device *bmac_devs = NULL;
+
+#if 0
+/*
+ * If we can't get a skbuff when we need it, we use this area for DMA.
+ */
+static unsigned char dummy_buf[RX_BUFLEN];
+#endif
+
+/*
+ * Number of bytes of private data per BMAC: allow enough for
+ * the rx and tx dma commands plus a branch dma command each,
+ * and another 16 bytes to allow us to align the dma command
+ * buffers on a 16 byte boundary.
+ */
+#define PRIV_BYTES	(sizeof(struct bmac_data) \
+			 + (N_RX_RING + N_TX_RING + 4) * sizeof(struct dbdma_cmd) \
+			 + sizeof(struct sk_buff_head))
+
+static unsigned char bitrev(unsigned char b);
+static int bmac_open(struct device *dev);
+static int bmac_close(struct device *dev);
+static int bmac_transmit_packet(struct sk_buff *skb, struct device *dev);
+static struct net_device_stats *bmac_stats(struct device *dev);
+static void bmac_set_multicast(struct device *dev);
+static int bmac_reset_and_enable(struct device *dev, int enable);
+static void bmac_start_chip(struct device *dev);
+static int bmac_init_chip(struct device *dev);
+static void bmac_init_registers(struct device *dev);
+static void bmac_reset_chip(struct device *dev);
+static int bmac_set_address(struct device *dev, void *addr);
+static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void bmac_set_timeout(struct device *dev);
+static void bmac_tx_timeout(unsigned long data);
+static void bmac_reset_chip(struct device *dev);
+static void bmac_init_registers(struct device *dev);
+static int bmac_proc_info ( char *buffer, char **start, off_t offset, int length, int dummy);
+static int bmac_output(struct sk_buff *skb, struct device *dev);
+static void bmac_start(struct device *dev);
+
+#define	DBDMA_SET(x)	( ((x) | (x) << 16) )
+#define	DBDMA_CLEAR(x)	( (x) << 16)
+
+static __inline__ void
+dbdma_st32(volatile unsigned long *a, unsigned long x)
+{
+	__asm__ volatile( "stwbrx %0,0,%1" : : "r" (x), "r" (a) : "memory");
+	return;
+}
+
+static __inline__ unsigned long
+dbdma_ld32(volatile unsigned long *a)
+{
+	unsigned long swap;
+	__asm__ volatile ("lwbrx %0,0,%1" :  "=r" (swap) : "r" (a));
+	return swap;
+}
+
+void
+dbdma_stop(volatile struct dbdma_regs *dmap)
+{
+	dbdma_st32((volatile unsigned long *)&dmap->control, DBDMA_CLEAR(RUN) | DBDMA_SET(FLUSH));
+	eieio();
+  
+	while (dbdma_ld32((volatile unsigned long *)&dmap->status) & (ACTIVE|FLUSH))
+		eieio();
+}
+
+static void
+dbdma_continue(volatile struct dbdma_regs *dmap)
+{
+	dbdma_st32((volatile unsigned long *)&dmap->control,
+		   DBDMA_SET(RUN|WAKE) | DBDMA_CLEAR(PAUSE|DEAD));
+	eieio();
+}
+
+static void
+dbdma_reset(volatile struct dbdma_regs *dmap)
+{
+	dbdma_st32((volatile unsigned long *)&dmap->control, 
+		   DBDMA_CLEAR(ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN));      
+	eieio();
+	while (dbdma_ld32((volatile unsigned long *)&dmap->status) & RUN) eieio();
+}
+
+static void
+dbdma_setcmd(volatile struct dbdma_cmd *cp,
+	     unsigned short cmd, unsigned count, unsigned long addr,
+	     unsigned long cmd_dep)
+{
+	out_le16(&cp->command, cmd);
+	out_le16(&cp->req_count, count);
+	out_le32(&cp->phy_addr, addr);
+	out_le32(&cp->cmd_dep, cmd_dep);
+	out_le16(&cp->xfer_status, 0);
+	out_le16(&cp->res_count, 0);
+}
+
+static __inline__
+void bmwrite(struct device *dev, unsigned long reg_offset, unsigned data )
+{
+	out_le16((void *)dev->base_addr + reg_offset, data);
+}
+
+
+static __inline__
+volatile unsigned short bmread(struct device *dev, unsigned long reg_offset )
+{
+	return in_le16((void *)dev->base_addr + reg_offset); 
+}
+
+static void
+bmac_reset_chip(struct device *dev)
+{
+	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	volatile struct dbdma_regs *rd = bp->rx_dma;
+	volatile struct dbdma_regs *td = bp->tx_dma;
+	volatile unsigned *heathrowFCR;
+	unsigned int fcrValue;
+	 
+	dbdma_reset(rd);
+	dbdma_reset(td);
+
+	heathrowFCR = (unsigned *)((unsigned char *)IoBaseHeathrow + HeathrowFCR);
+
+	fcrValue = in_le32(heathrowFCR);
+
+	fcrValue &= fcrDisableEnet;	/* clear out Xvr and Controller Bit */
+	out_le32(heathrowFCR, fcrValue);
+	udelay(50000);
+
+	fcrValue |= fcrResetEnetCell;	/* set bit to reset them */
+	out_le32(heathrowFCR, fcrValue);
+	udelay(50000);
+	
+	fcrValue &= fcrDisableEnet;
+	out_le32(heathrowFCR, fcrValue);
+	udelay(50000);
+
+	fcrValue |= fcrEnetEnabledBits;
+	out_le32(heathrowFCR, fcrValue);
+	udelay(50000);
+	
+	out_le32(heathrowFCR, fcrValue);
+}
+
+static void
+bmac_init_registers(struct device *dev)
+{
+	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	volatile unsigned short regValue;
+	unsigned short *pWord16;
+	int i;
+
+/* XXDEBUG(("bmac: enter init_registers\n")); */
+
+	bmwrite(dev, TXRST, TxResetBit);
+
+	do {
+		regValue = bmread(dev, TXRST); /* wait for reset to clear..acknowledge */
+	} while (regValue & TxResetBit);
+
+	bmwrite(dev, RXRST, RxResetValue);
+	bmwrite(dev, XCVRIF, ClkBit | SerialMode | COLActiveLow);	
+	bmwrite(dev, RSEED, (unsigned short)0x1968);		
+
+	regValue = bmread(dev, XIFC);
+	regValue |= TxOutputEnable;
+	bmwrite(dev, XIFC, regValue);
+
+	bmread(dev, PAREG);
+
+	/* set collision counters to 0 */
+	bmwrite(dev, NCCNT, 0);
+	bmwrite(dev, NTCNT, 0);
+	bmwrite(dev, EXCNT, 0);
+	bmwrite(dev, LTCNT, 0);
+
+	/* set rx counters to 0 */
+	bmwrite(dev, FRCNT, 0);
+	bmwrite(dev, LECNT, 0);
+	bmwrite(dev, AECNT, 0);
+	bmwrite(dev, FECNT, 0);
+	bmwrite(dev, RXCV, 0);
+
+	/* set tx fifo information */
+	bmwrite(dev, TXTH, 4);	/* 4 octets before tx starts */
+
+	bmwrite(dev, TXFIFOCSR, 0);	/* first disable txFIFO */
+	bmwrite(dev, TXFIFOCSR, TxFIFOEnable );
+
+	/* set rx fifo information */
+	bmwrite(dev, RXFIFOCSR, 0);	/* first disable rxFIFO */
+	bmwrite(dev, RXFIFOCSR, RxFIFOEnable ); 
+
+	//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 */
+	bmwrite(dev, BHASH2, bp->hash_table_mask[1]); 	/* bits 31 - 16 */
+	bmwrite(dev, BHASH1, bp->hash_table_mask[2]); 	/* bits 47 - 32 */
+	bmwrite(dev, BHASH0, bp->hash_table_mask[3]); 	/* bits 63 - 48 */
+	
+	pWord16 = (unsigned short *)dev->dev_addr;
+	bmwrite(dev, MADD0, *pWord16++);
+	bmwrite(dev, MADD1, *pWord16++);
+	bmwrite(dev, MADD2, *pWord16);
+    
+
+	bmwrite(dev, RXCFG, RxCRCNoStrip | RxHashFilterEnable | RxRejectOwnPackets);
+    
+	return;
+}
+
+#if 0
+static void
+bmac_disable_interrupts(struct device *dev)
+{
+	bmwrite(dev, INTDISABLE, DisableAll);
+}
+
+static void
+bmac_enable_interrupts(struct device *dev)
+{
+	bmwrite(dev, INTDISABLE, EnableNormal);
+}
+#endif
+
+
+static void
+bmac_start_chip(struct device *dev)
+{
+	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	volatile struct dbdma_regs *rd = bp->rx_dma;
+	unsigned short	oldConfig;
+
+	/* enable rx dma channel */
+	dbdma_continue(rd);
+  
+	/* turn on rx plus any other bits already on (promiscuous possibly) */
+	oldConfig = bmread(dev, RXCFG);		
+	bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); 
+ 
+	oldConfig = bmread(dev, TXCFG);		
+	bmwrite(dev, TXCFG, oldConfig | TxMACEnable );  
+}
+
+static int
+bmac_init_chip(struct device *dev)
+{
+	bmac_init_registers(dev);
+	return 1;
+}
+
+static int bmac_set_address(struct device *dev, void *addr)
+{
+	unsigned char *p = addr;
+	unsigned short *pWord16;
+	unsigned long flags;
+	int i;
+
+	XXDEBUG(("bmac: enter set_address\n"));
+	save_flags(flags); cli();
+
+	for (i = 0; i < 6; ++i) {
+		dev->dev_addr[i] = p[i];
+	}
+	/* load up the hardware address */
+	pWord16  = (unsigned short *)dev->dev_addr;
+	bmwrite(dev, MADD0, *pWord16++);
+	bmwrite(dev, MADD1, *pWord16++);
+	bmwrite(dev, MADD2, *pWord16);
+
+	restore_flags(flags);
+	XXDEBUG(("bmac: exit set_address\n"));
+	return 0;
+}
+
+static inline void bmac_set_timeout(struct device *dev)
+{
+	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	if (bp->timeout_active)
+		del_timer(&bp->tx_timeout);
+	bp->tx_timeout.expires = jiffies + TX_TIMEOUT;
+	bp->tx_timeout.function = bmac_tx_timeout;
+	bp->tx_timeout.data = (unsigned long) dev;
+	add_timer(&bp->tx_timeout);
+	bp->timeout_active = 1;
+	restore_flags(flags);
+}
+
+static void
+bmac_construct_xmt(struct sk_buff *skb, volatile struct dbdma_cmd *cp,
+		   char *doubleBuf)
+{
+	void *vaddr, *page_break;
+	unsigned long baddr;
+	unsigned long len;
+
+	len = skb->len;
+	vaddr = skb->data;
+	baddr = virt_to_bus(vaddr);
+	page_break = round_page(vaddr);
+	if (trunc_page(vaddr) != trunc_page(vaddr+len) &&
+	    (unsigned long)round_page(baddr) != virt_to_bus(page_break))  {
+		baddr = virt_to_bus(doubleBuf);
+		XXDEBUG(("bmac: double buffering, double=%#08x, skb->data=%#08x, len=%d\n", doubleBuf, skb->data, len));
+	} else
+		flush_page_to_ram((unsigned long)vaddr);
+
+	dbdma_setcmd(cp, (OUTPUT_LAST | INTR_ALWAYS | WAIT_IFCLR), len, baddr, 0);
+}
+
+static void
+bmac_construct_rxbuff(unsigned char *addr, volatile struct dbdma_cmd *cp)
+{
+	dbdma_setcmd(cp, (INPUT_LAST | INTR_ALWAYS), RX_BUFLEN, virt_to_bus(addr), 0);
+}
+
+/* Bit-reverse one byte of an ethernet hardware address. */
+static unsigned char
+bitrev(unsigned char b)
+{
+	int d = 0, i;
+
+	for (i = 0; i < 8; ++i, b >>= 1)
+		d = (d << 1) | (b & 1);
+	return d;
+}
+
+
+static int
+bmac_init_tx_ring(struct bmac_data *bp)
+{
+	int i;
+	volatile struct dbdma_regs *td = bp->tx_dma;
+	char *addr;
+
+	if (!bp->tx_allocated) {
+		/* zero out tx cmds, alloc space for double buffering */
+		addr = (char *)kmalloc(ETHERMTU * N_TX_RING, GFP_DMA);
+		for (i = 0; i < N_TX_RING; i++, addr += ETHERMTU) bp->tx_double[i] = addr;
+		bp->tx_allocated = 1;
+	}
+	memset((char *)bp->tx_cmds, 0, (N_TX_RING+1) * sizeof(struct dbdma_cmd));
+
+	bp->tx_empty = 0;
+	bp->tx_fill = 0;
+	bp->tx_fullup = 0;
+
+	/* put a branch at the end of the tx command list */
+	dbdma_setcmd(&bp->tx_cmds[N_TX_RING],
+		     (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->tx_cmds));
+
+	/* reset tx dma */
+	dbdma_reset(td);
+	out_le32(&td->wait_sel, 0x00200020);
+	out_le32(&td->cmdptr, virt_to_bus(bp->tx_cmds));
+
+	return 1;
+
+}
+
+static int
+bmac_init_rx_ring(struct bmac_data *bp)
+{
+	volatile struct dbdma_regs *rd = bp->rx_dma;
+	int i;
+
+	/* initialize list of sk_buffs for receiving and set up recv dma */
+	if (!bp->rx_allocated) {
+		for (i = 0; i < N_RX_RING; i++) {
+			bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2);
+			skb_reserve(bp->rx_bufs[i], 2);
+		}
+		bp->rx_allocated = 1;
+	}
+
+	memset((char *)bp->rx_cmds, 0, (N_RX_RING+1) * sizeof(struct dbdma_cmd));
+	for (i = 0; i < N_RX_RING; i++)
+		bmac_construct_rxbuff(bp->rx_bufs[i]->data, &bp->rx_cmds[i]);
+
+	bp->rx_empty = 0;
+	bp->rx_fill = i;
+
+	/* Put a branch back to the beginning of the receive command list */
+	dbdma_setcmd(&bp->rx_cmds[N_RX_RING],
+		     (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->rx_cmds));
+
+	/* start rx dma */
+	dbdma_reset(rd);
+	out_le32(&rd->cmdptr, virt_to_bus(bp->rx_cmds));
+
+	return 1;
+}
+
+
+static int bmac_transmit_packet(struct sk_buff *skb, struct device *dev)
+{
+	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	volatile struct dbdma_regs *td = bp->tx_dma;
+	int i;
+
+	/* see if there's a free slot in the tx ring */
+/* XXDEBUG(("bmac_xmit_start: empty=%d fill=%d\n", */
+/* 	     bp->tx_empty, bp->tx_fill)); */
+	i = bp->tx_fill + 1;
+	if (i >= N_TX_RING) i = 0;
+	if (i == bp->tx_empty) {
+		dev->tbusy = 1;
+		bp->tx_fullup = 1;
+		XXDEBUG(("bmac_transmit_packet: tx ring full\n"));
+		return -1;		/* can't take it at the moment */
+	}
+
+	dbdma_setcmd(&bp->tx_cmds[i], DBDMA_STOP, 0, 0, 0);
+
+	bmac_construct_xmt(skb, &bp->tx_cmds[bp->tx_fill], bp->tx_double[bp->tx_fill]);
+
+	bp->tx_bufs[bp->tx_fill] = skb;
+	bp->tx_fill = i;
+
+	dbdma_continue(td);
+
+	return 0;
+}
+
+static int rxintcount = 0;
+
+static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct device *dev = (struct device *) dev_id;
+	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	volatile struct dbdma_regs *rd = bp->rx_dma;
+	volatile struct dbdma_cmd *cp;
+	int i, nb, stat;
+	struct sk_buff *skb;
+	unsigned int residual;
+	int last;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+
+	if (++rxintcount < 10) {
+		XXDEBUG(("bmac_rxdma_intr\n"));
+	}
+
+	last = -1;
+	i = bp->rx_empty;
+
+	while (1) {
+		cp = &bp->rx_cmds[i];
+		stat = ld_le16(&cp->xfer_status);
+		residual = ld_le16(&cp->res_count);
+		if ((stat & ACTIVE) == 0) break;
+		nb = RX_BUFLEN - residual - 2;
+		if (nb < (ETHERMINPACKET - ETHERCRC)) {
+			skb = NULL;
+			bp->stats.rx_length_errors++;
+			bp->stats.rx_errors++;
+		} else skb =  bp->rx_bufs[i];
+		if (skb != NULL) {
+			nb -= ETHERCRC;
+			skb_put(skb, nb);
+			skb->dev = dev;
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+			bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2);
+			skb_reserve(bp->rx_bufs[i], 2);
+			bmac_construct_rxbuff(bp->rx_bufs[i]->data, &bp->rx_cmds[i]);
+			++bp->stats.rx_packets;
+		} else {
+			++bp->stats.rx_dropped;
+		}
+		st_le16(&cp->res_count, 0);
+		st_le16(&cp->xfer_status, 0);
+		last = i;
+		if (++i >= N_RX_RING) i = 0;
+	}
+
+	if (last != -1) {
+		bp->rx_fill = last;
+		bp->rx_empty = i;
+	}
+
+	restore_flags(flags);
+
+	dbdma_continue(rd);
+
+	if (rxintcount < 10) {
+		XXDEBUG(("bmac_rxdma_intr done\n"));
+	}
+}
+
+static int txintcount = 0;
+
+static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct device *dev = (struct device *) dev_id;
+	struct bmac_data *bp = (struct bmac_data *) dev->priv;
+	volatile struct dbdma_cmd *cp;
+	int stat;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+
+	if (txintcount++ < 10) {
+		XXDEBUG(("bmac_txdma_intr\n"));
+	}
+
+/*     del_timer(&bp->tx_timeout); */
+/*     bp->timeout_active = 0; */
+
+	while (1) {
+		cp = &bp->tx_cmds[bp->tx_empty];
+		stat = ld_le16(&cp->xfer_status);
+		if (txintcount < 10) {
+			XXDEBUG(("bmac_txdma_xfer_stat=%#0x\n", stat));
+		}
+		if (!(stat & ACTIVE)) break;
+
+		if (bp->tx_bufs[bp->tx_empty]) {
+			++bp->stats.tx_packets;
+			dev_kfree_skb(bp->tx_bufs[bp->tx_empty]);
+		}
+		bp->tx_bufs[bp->tx_empty] = NULL;
+		bp->tx_fullup = 0;
+		dev->tbusy = 0;
+/* XXDEBUG(("bmac_intr: cleared tbusy, empty=%d fill=%d\n", */
+/* 		 i, bp->tx_fill)); */
+		mark_bh(NET_BH);
+		if (++bp->tx_empty >= N_TX_RING) bp->tx_empty = 0;
+		if (bp->tx_empty == bp->tx_fill) break;
+	}
+
+	restore_flags(flags);
+
+	if (txintcount < 10) {
+		XXDEBUG(("bmac_txdma_intr done->bmac_start\n"));
+	}
+
+	bmac_start(dev);
+}
+
+static struct net_device_stats *bmac_stats(struct device *dev)
+{
+	struct bmac_data *p = (struct bmac_data *) dev->priv;
+
+	return &p->stats;
+}
+
+#if 0
+/* Real fast bit-reversal algorithm, 6-bit values */
+static int reverse6[64] = {
+	0x0,0x20,0x10,0x30,0x8,0x28,0x18,0x38,
+	0x4,0x24,0x14,0x34,0xc,0x2c,0x1c,0x3c,
+	0x2,0x22,0x12,0x32,0xa,0x2a,0x1a,0x3a,
+	0x6,0x26,0x16,0x36,0xe,0x2e,0x1e,0x3e,
+	0x1,0x21,0x11,0x31,0x9,0x29,0x19,0x39,
+	0x5,0x25,0x15,0x35,0xd,0x2d,0x1d,0x3d,
+	0x3,0x23,0x13,0x33,0xb,0x2b,0x1b,0x3b,
+	0x7,0x27,0x17,0x37,0xf,0x2f,0x1f,0x3f
+};
+
+static unsigned int
+crc416(unsigned int curval, unsigned short nxtval)
+{
+	register unsigned int counter, cur = curval, next = nxtval;
+	register int high_crc_set, low_data_set;
+
+	/* Swap bytes */
+	next = ((next & 0x00FF) << 8) | (next >> 8);
+
+	/* Compute bit-by-bit */
+	for (counter = 0; counter < 16; ++counter) {
+		/* is high CRC bit set? */
+		if ((cur & 0x80000000) == 0) high_crc_set = 0;
+		else high_crc_set = 1;
+      
+		cur = cur << 1;
+	
+		if ((next & 0x0001) == 0) low_data_set = 0;
+		else low_data_set = 1;
+
+		next = next >> 1;
+	
+		/* do the XOR */
+		if (high_crc_set ^ low_data_set) cur = cur ^ ENET_CRCPOLY;
+	}
+	return cur;
+}
+
+static unsigned int
+bmac_crc(unsigned short *address)
+{	
+	unsigned int newcrc;
+
+	XXDEBUG(("bmac_crc: addr=%#04x, %#04x, %#04x\n", *address, address[1], address[2]));
+	newcrc = crc416(0xffffffff, *address);	/* address bits 47 - 32 */
+	newcrc = crc416(newcrc, address[1]);	/* address bits 31 - 16 */
+	newcrc = crc416(newcrc, address[2]);	/* address bits 15 - 0  */
+
+	return(newcrc);
+}
+
+/*
+ * Add requested mcast addr to BMac's hash table filter.  
+ *  
+ */
+
+static void
+bmac_addhash(struct bmac_data *bp, unsigned char *addr)
+{	
+	unsigned int	 crc;
+	unsigned short	 mask;
+
+	if (!(*addr 
+	      crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */
+	      crc = reverse6[crc];	/* Hyperfast bit-reversing algorithm */
+	      if (bp->hash_use_count[crc]++) return; /* This bit is already set */
+	      mask = crc % 16;
+	      mask = (unsigned char)1 << mask;
+	      bp->hash_use_count[crc/16] |= mask;
+	      }
+
+	    static void
+	    bmac_removehash(struct bmac_data *bp, unsigned char *addr)
+	    {	
+		    unsigned int crc;
+		    unsigned char mask;
+
+		    /* Now, delete the address from the filter copy, as indicated */
+		    crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */
+		    crc = reverse6[crc];	/* Hyperfast bit-reversing algorithm */
+		    if (bp->hash_use_count[crc] == 0) return; /* That bit wasn't in use! */
+		    if (--bp->hash_use_count[crc]) return; /* That bit is still in use */
+		    mask = crc % 16;
+		    mask = ((unsigned char)1 << mask) ^ 0xffff; /* To turn off bit */
+		    bp->hash_table_mask[crc/16] &= mask;
+	    }
+
+/*
+ * Sync the adapter with the software copy of the multicast mask
+ *  (logical address filter).
+ */
+
+		    static void
+		    bmac_rx_off(struct device *dev)
+		    {
+			    unsigned short rx_cfg;
+
+			    rx_cfg = bmread(dev, RXCFG);
+			    rx_cfg &= ~RxMACEnable;
+			    bmwrite(dev, RXCFG, rx_cfg);
+			    do {
+				    rx_cfg = bmread(dev, RXCFG);
+			    }  while (rx_cfg & RxMACEnable);
+		    }
+
+			    unsigned short
+			    bmac_rx_on(struct device *dev, int hash_enable, int promisc_enable)
+			    {
+				    unsigned short rx_cfg;
+
+				    rx_cfg = bmread(dev, RXCFG);
+				    rx_cfg |= RxMACEnable;
+				    if (hash_enable) rx_cfg |= RxHashFilterEnable;
+				    else rx_cfg &= ~RxHashFilterEnable;
+				    if (promisc_enable) rx_cfg |= RxPromiscEnable;
+				    else rx_cfg &= ~RxPromiscEnable;
+				    bmwrite(dev, RXRST, RxResetValue);
+				    bmwrite(dev, RXFIFOCSR, 0);	/* first disable rxFIFO */
+				    bmwrite(dev, RXFIFOCSR, RxFIFOEnable ); 
+				    bmwrite(dev, RXCFG, rx_cfg );
+				    return rx_cfg;
+			    }
+
+				    static void
+				    bmac_update_hash_table_mask(struct device *dev, struct bmac_data *bp)
+				    {
+					    bmwrite(dev, BHASH3, bp->hash_table_mask[0]); /* bits 15 - 0 */
+					    bmwrite(dev, BHASH2, bp->hash_table_mask[1]); /* bits 31 - 16 */
+					    bmwrite(dev, BHASH1, bp->hash_table_mask[2]); /* bits 47 - 32 */
+					    bmwrite(dev, BHASH0, bp->hash_table_mask[3]); /* bits 63 - 48 */
+				    }
+
+#if 0
+					    static void
+					    bmac_add_multi(struct device *dev,
+							   struct bmac_data *bp, unsigned char *addr)
+					    {
+/* XXDEBUG(("bmac: enter bmac_add_multi\n")); */
+						    bmac_addhash(bp, addr);
+						    bmac_rx_off(dev);
+						    bmac_update_hash_table_mask(dev, bp);
+						    bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0);
+/* XXDEBUG(("bmac: exit bmac_add_multi\n")); */
+					    }
+
+						    static void
+						    bmac_remove_multi(struct device *dev,
+								      struct bmac_data *bp, unsigned char *addr)
+						    {
+							    bmac_removehash(bp, addr);
+							    bmac_rx_off(dev);
+							    bmac_update_hash_table_mask(dev, bp);
+							    bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0);
+						    }
+#endif
+
+/* Set or clear the multicast filter for this adaptor.
+    num_addrs == -1	Promiscuous mode, receive all packets
+    num_addrs == 0	Normal mode, clear multicast list
+    num_addrs > 0	Multicast mode, receive normal and MC packets, and do
+			best-effort filtering.
+ */
+							    static void bmac_set_multicast(struct device *dev)
+							    {
+								    struct dev_mc_list *dmi;
+								    struct bmac_data *bp = (struct bmac_data *) dev->priv;
+								    int num_addrs = dev->mc_count;
+								    unsigned short rx_cfg;
+								    int i;
+
+								    XXDEBUG(("bmac: enter bmac_set_multicast, n_addrs=%d\n", num_addrs));
+
+								    if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
+									    for (i=0; i<4; i++) bp->hash_table_mask[i] = 0xffff;
+									    bmac_update_hash_table_mask(dev, bp);
+									    rx_cfg = bmac_rx_on(dev, 1, 0);
+									    XXDEBUG(("bmac: all multi, rx_cfg=%#08x\n"));
+								    } else if if ((dev->flags & IFF_PROMISC) || (num_addrs < 0)) {
+									    rx_cfg = bmread(dev, RXCFG);
+									    rx_cfg |= RxPromiscEnable;
+									    bmwrite(dev, RXCFG, rx_cfg);
+									    rx_cfg = bmac_rx_on(dev, 0, 1);
+									    XXDEBUG(("bmac: promisc mode enabled, rx_cfg=%#08x\n", rx_cfg));
+								    } else {
+									    for (i=0; i<4; i++) bp->hash_table_mask[i] = 0;
+									    for (i=0; i<64; i++) bp->hash_use_count[i] = 0;
+									    if (num_addrs == 0) {
+										    rx_cfg = bmac_rx_on(dev, 0, 0);
+										    XXDEBUG(("bmac: multi disabled, rx_cfg=%#08x\n", rx_cfg));
+									    } else {
+										    for (dmi=dev->mc_list; dmi!=NULL; dmi=dmi->next)
+											    bmac_addhash(bp, dmi->dmi_addr);
+										    bmac_update_hash_table_mask(dev, bp);
+										    rx_cfg = bmac_rx_on(dev, 1, 0);
+										    XXDEBUG(("bmac: multi enabled, rx_cfg=%#08x\n", rx_cfg));
+									    }
+								    }
+/* XXDEBUG(("bmac: exit bmac_set_multicast\n")); */
+							    }
+#endif
+
+/* The version of set_multicast below was lifted from sunhme.c */
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
+
+								    static void bmac_set_multicast(struct device *dev)
+								    {
+									    struct dev_mc_list *dmi = dev->mc_list;
+									    char *addrs;
+									    int i, j, bit, byte;
+									    unsigned short rx_cfg;
+									    u32 crc, poly = CRC_POLYNOMIAL_LE;
+    
+									    /* Let the transmits drain. */
+/*     while(dev->tbusy) schedule(); */
+    
+									    /* Lock out others. */
+/*     set_bit(0, (void *) &dev->tbusy); */
+    
+									    if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
+										    bmwrite(dev, BHASH0, 0xffff);
+										    bmwrite(dev, BHASH1, 0xffff);
+										    bmwrite(dev, BHASH2, 0xffff);
+										    bmwrite(dev, BHASH3, 0xffff);
+									    } else if(dev->flags & IFF_PROMISC) {
+										    rx_cfg = bmread(dev, RXCFG);
+										    rx_cfg |= RxPromiscEnable;
+										    bmwrite(dev, RXCFG, rx_cfg);
+									    } else {
+										    u16 hash_table[4];
+	
+										    for(i = 0; i < 4; i++) hash_table[i] = 0;
+	
+										    for(i = 0; i < dev->mc_count; i++) {
+											    addrs = dmi->dmi_addr;
+											    dmi = dmi->next;
+	    
+											    if(!(*addrs & 1))
+												    continue;
+	    
+											    crc = 0xffffffffU;
+											    for(byte = 0; byte < 6; byte++) {
+												    for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
+													    int test;
+		    
+													    test = ((bit ^ crc) & 0x01);
+													    crc >>= 1;
+													    if(test)
+														    crc = crc ^ poly;
+												    }
+											    }
+											    crc >>= 26;
+											    hash_table[crc >> 4] |= 1 << (crc & 0xf);
+										    }
+										    bmwrite(dev, BHASH0, hash_table[0]);
+										    bmwrite(dev, BHASH1, hash_table[1]);
+										    bmwrite(dev, BHASH2, hash_table[2]);
+										    bmwrite(dev, BHASH3, hash_table[3]);
+									    }
+    
+									    /* Let us get going again. */
+/*     dev->tbusy = 0; */
+								    }
+
+
+									    static int miscintcount = 0;
+
+									    static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs)
+									    {
+										    struct device *dev = (struct device *) dev_id;
+										    struct bmac_data *bp = (struct bmac_data *)dev->priv;
+										    unsigned int status = bmread(dev, STATUS);
+										    if (miscintcount++ < 10) {
+											    XXDEBUG(("bmac_misc_intr\n"));
+										    }
+/* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */
+/*     bmac_txdma_intr_inner(irq, dev_id, regs); */
+/*   if (status & FrameReceived) bp->stats.rx_dropped++; */
+										    if (status & RxErrorMask) bp->stats.rx_errors++;
+										    if (status & RxCRCCntExp) bp->stats.rx_crc_errors++;
+										    if (status & RxLenCntExp) bp->stats.rx_length_errors++;
+										    if (status & RxOverFlow) bp->stats.rx_over_errors++;
+										    if (status & RxAlignCntExp) bp->stats.rx_frame_errors++;
+
+/*   if (status & FrameSent) bp->stats.tx_dropped++; */
+										    if (status & TxErrorMask) bp->stats.tx_errors++;
+										    if (status & TxUnderrun) bp->stats.tx_fifo_errors++;
+										    if (status & TxNormalCollExp) bp->stats.collisions++;
+									    }
+
+/*
+ * Procedure for reading EEPROM 
+ */
+#define SROMAddressLength	5
+#define DataInOn		0x0008
+#define DataInOff		0x0000
+#define Clk			0x0002
+#define ChipSelect		0x0001
+#define SDIShiftCount		3
+#define SD0ShiftCount		2
+#define	DelayValue		1000	/* number of microseconds */
+#define SROMStartOffset		10	/* this is in words */
+#define SROMReadCount		3	/* number of words to read from SROM */
+#define SROMAddressBits		6
+#define EnetAddressOffset	20
+
+										    static unsigned char
+										    bmac_clock_out_bit(struct device *dev)
+										    {
+											    unsigned short         data;
+											    unsigned short         val;
+
+											    bmwrite(dev, SROMCSR, ChipSelect | Clk);
+											    udelay(DelayValue);
+    
+											    data = bmread(dev, SROMCSR);
+											    udelay(DelayValue);
+											    val = (data >> SD0ShiftCount) & 1;
+
+											    bmwrite(dev, SROMCSR, ChipSelect);
+											    udelay(DelayValue);
+    
+											    return val;
+										    }
+
+											    static void
+											    bmac_clock_in_bit(struct device *dev, unsigned int val)
+											    {
+												    unsigned short		data;    
+
+												    if (val != 0 && val != 1) return;
+    
+												    data = (val << SDIShiftCount);
+												    bmwrite(dev, SROMCSR, data | ChipSelect  );
+												    udelay(DelayValue);
+    
+												    bmwrite(dev, SROMCSR, data | ChipSelect | Clk );
+												    udelay(DelayValue);
+
+												    bmwrite(dev, SROMCSR, data | ChipSelect);
+												    udelay(DelayValue);
+											    }
+
+												    static void
+												    reset_and_select_srom(struct device *dev)
+												    {
+													    /* first reset */
+													    bmwrite(dev, SROMCSR, 0);
+													    udelay(DelayValue);
+    
+													    /* send it the read command (110) */
+													    bmac_clock_in_bit(dev, 1);
+													    bmac_clock_in_bit(dev, 1);
+													    bmac_clock_in_bit(dev, 0);
+												    }
+
+													    static unsigned short
+													    read_srom(struct device *dev, unsigned int addr, unsigned int addr_len)
+													    {
+														    unsigned short data, val;
+														    int i;
+    
+														    /* send out the address we want to read from */
+														    for (i = 0; i < addr_len; i++)	{
+															    val = addr >> (addr_len-i-1);
+															    bmac_clock_in_bit(dev, val & 1);
+														    }
+    
+														    /* Now read in the 16-bit data */
+														    data = 0;
+														    for (i = 0; i < 16; i++)	{
+															    val = bmac_clock_out_bit(dev);
+															    data <<= 1;
+															    data |= val;
+														    }
+														    bmwrite(dev, SROMCSR, 0);
+    
+														    return data;
+													    }
+
+/*
+ * It looks like Cogent and SMC use different methods for calculating
+ * checksums. What a pain.. 
+ */
+
+														    static int
+														    bmac_verify_checksum(struct device *dev)
+														    {
+															    unsigned short data, storedCS;
+    
+															    reset_and_select_srom(dev);
+															    data = read_srom(dev, 3, SROMAddressBits);
+															    storedCS = ((data >> 8) & 0x0ff) | ((data << 8) & 0xff00);
+    
+															    return 0;
+														    }
+
+
+															    static void
+															    bmac_get_station_address(struct device *dev, unsigned char *ea)
+															    {
+																    int i;
+																    unsigned short data;
+
+																    for (i = 0; i < 6; i++)	
+																    {
+																	    reset_and_select_srom(dev);
+																	    data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits);
+																	    ea[2*i]   = bitrev(data & 0x0ff);
+																	    ea[2*i+1] = bitrev((data >> 8) & 0x0ff);
+																    }
+															    }
+
+																    static int bmac_reset_and_enable(struct device *dev, int enable)
+																    {
+																	    struct bmac_data *bp = dev->priv;
+																	    unsigned long flags;
+
+																	    save_flags(flags); cli();
+																	    bp->reset_and_enabled = 0;
+																	    bmac_reset_chip(dev);
+																	    if (enable) {
+																		    if (!bmac_init_tx_ring(bp) || !bmac_init_rx_ring(bp)) return 0;
+																		    if (!bmac_init_chip(dev)) return 0;
+																		    bmac_start_chip(dev);
+																		    bmwrite(dev, INTDISABLE, EnableNormal);
+																		    bp->reset_and_enabled = 1;
+/* 	{ */
+/* 	    unsigned char random_packet[100]; */
+/* 	    unsigned int i; */
+/* 	    struct sk_buff *skb = dev_alloc_skb(RX_BUFLEN+2); */
+/* 	    unsigned char *data = skb_put(skb, sizeof(random_packet)); */
+/* XXDEBUG(("transmitting random packet\n")); */
+/* 	    for (i = 0; i < sizeof(random_packet); i++) data[i] = i; */
+/* 	    bmac_transmit_packet(skb, dev); */
+/* XXDEBUG(("done transmitting random packet\n")); */
+/* 	} */
+																	    }
+																	    restore_flags(flags);
+																	    return 1;
+																    }
+
+																	    int
+																	    bmac_probe(struct device *dev)
+																	    {
+																		    int j, rev;
+																		    struct bmac_data *bp;
+																		    struct device_node *bmacs;
+																		    unsigned char *addr;
+
+																		    bmacs = find_devices("bmac");
+																		    if (bmacs == NULL) return ENODEV;
+
+																		    bmac_devs = dev; /* KLUDGE!! */
+
+																		    if (bmacs->n_addrs != 3 || bmacs->n_intrs != 3) {
+																			    printk(KERN_ERR "can't use BMAC %s: expect 3 addrs and 3 intrs\n",
+																				   bmacs->full_name);
+																			    return EINVAL;
+																		    }
+    
+																		    if (dev == NULL) {
+																			    dev = init_etherdev(NULL, PRIV_BYTES);
+																			    bmac_devs = dev;  /*KLUDGE!!*/
+																		    } else {
+																			    /* XXX this doesn't look right (but it's never used :-) */
+																			    dev->priv = kmalloc(PRIV_BYTES, GFP_KERNEL);
+																			    if (dev->priv == 0) return -ENOMEM;
+																		    }
+    
+																		    dev->base_addr = bmacs->addrs[0].address;
+																		    dev->irq = bmacs->intrs[0].line;
+    
+																		    bmwrite(dev, INTDISABLE, DisableAll);
+
+																		    if (request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev)) {
+																			    printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq);
+																			    return -EAGAIN;
+																		    }
+																		    if (request_irq(bmacs->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma",
+																				    dev)) {
+																			    printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[1].line);
+																			    return -EAGAIN;
+																		    }
+																		    if (request_irq(bmacs->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma",
+																				    dev)) {
+																			    printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[2].line);
+																			    return -EAGAIN;
+																		    }
+    
+																		    addr = get_property(bmacs, "mac-address", NULL);
+																		    if (addr == NULL) {
+																			    addr = get_property(bmacs, "local-mac-address", NULL);
+																			    if (addr == NULL) {
+																				    printk(KERN_ERR "Can't get mac-address for BMAC at %lx\n",
+																					   dev->base_addr);
+																				    return -EAGAIN;
+																			    }
+																		    }
+    
+																		    printk(KERN_INFO "%s: BMAC at", dev->name);
+																		    rev = addr[0] == 0 && addr[1] == 0xA0;
+																		    for (j = 0; j < 6; ++j) {
+																			    dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+																			    printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
+																		    }
+																		    XXDEBUG((", base_addr=%#0lx", dev->base_addr));
+																		    printk("\n");
+    
+																		    dev->open = bmac_open;
+																		    dev->stop = bmac_close;
+																		    dev->hard_start_xmit = bmac_output;
+																		    dev->get_stats = bmac_stats;
+																		    dev->set_multicast_list = bmac_set_multicast;
+																		    dev->set_mac_address = bmac_set_address;
+
+																		    bmac_get_station_address(dev, addr);
+																		    if (bmac_verify_checksum(dev) != 0) return EINVAL;
+    
+																		    ether_setup(dev);
+    
+																		    bp = (struct bmac_data *) dev->priv;
+																		    memset(bp, 0, sizeof(struct bmac_data));
+																		    bp->tx_dma = (volatile struct dbdma_regs *) bmacs->addrs[1].address;
+																		    bp->tx_dma_intr = bmacs->intrs[1].line;
+																		    bp->rx_dma = (volatile struct dbdma_regs *) bmacs->addrs[2].address;
+																		    bp->rx_dma_intr = bmacs->intrs[2].line;
+    
+																		    bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1);
+																		    bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1;
+
+																		    bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1);
+																		    skb_queue_head_init(bp->queue);
+    
+																		    memset(&bp->stats, 0, sizeof(bp->stats));
+																		    memset((char *) bp->tx_cmds, 0,
+																			   (N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
+/*     init_timer(&bp->tx_timeout); */
+/*     bp->timeout_active = 0; */
+    
+																		    if (!bmac_reset_and_enable(dev, 0)) return EINVAL;
+
+#ifdef CONFIG_PROC_FS
+																		    proc_net_register(&(struct proc_dir_entry) {
+																			    PROC_NET_BMAC, 4, "bmac",
+																				    S_IFREG | S_IRUGO, 1, 0, 0,
+																				    0, &proc_net_inode_operations,
+																				    bmac_proc_info
+																				    });
+#endif
+
+																		    return 0;
+																	    }
+
+																		    static int bmac_open(struct device *dev)
+																		    {
+/* XXDEBUG(("bmac: enter open\n")); */
+																			    /* reset the chip */
+																			    bmac_reset_and_enable(dev, 1);
+
+																			    dev->flags |= IFF_UP | IFF_RUNNING;
+
+																			    return 0;
+																		    }
+
+																			    static int bmac_close(struct device *dev)
+																			    {
+																				    struct bmac_data *bp = (struct bmac_data *) dev->priv;
+																				    volatile struct dbdma_regs *rd = bp->rx_dma;
+																				    volatile struct dbdma_regs *td = bp->tx_dma;
+																				    unsigned short config;
+																				    int i;
+
+																				    dev->flags &= ~(IFF_UP | IFF_RUNNING);
+
+																				    /* disable rx and tx */
+																				    config = bmread(dev, RXCFG);
+																				    bmwrite(dev, RXCFG, (config & ~RxMACEnable));
+
+																				    config = bmread(dev, TXCFG);
+																				    bmwrite(dev, TXCFG, (config & ~TxMACEnable));
+
+																				    bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */
+
+																				    /* disable rx and tx dma */
+																				    st_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
+																				    st_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
+
+																				    /* free some skb's */
+																				    XXDEBUG(("bmac: free rx bufs\n"));
+																				    for (i=0; i<N_RX_RING; i++) {
+																					    if (bp->rx_bufs[i] != NULL) {
+																						    dev_kfree_skb(bp->rx_bufs[i]);
+																						    bp->rx_bufs[i] = NULL;
+																					    }
+																				    }
+																				    bp->rx_allocated = 0;
+																				    XXDEBUG(("bmac: free doubles\n"));/*MEMORY LEAK BELOW!!! FIX!!! */
+																				    if (bp->tx_double[0] != NULL) kfree(bp->tx_double[0]);
+																				    XXDEBUG(("bmac: free tx bufs\n"));
+																				    for (i = 0; i<N_TX_RING; i++) {
+																					    if (bp->tx_bufs[i] != NULL) {
+																						    dev_kfree_skb(bp->tx_bufs[i]);
+																						    bp->tx_bufs[i] = NULL;
+																					    }
+																				    }
+																				    bp->tx_allocated = 0;
+																				    bp->reset_and_enabled = 0;
+																				    XXDEBUG(("bmac: all bufs freed\n"));
+
+																				    return 0;
+																			    }
+
+																				    static void
+																				    bmac_start(struct device *dev)
+																				    {
+																					    struct bmac_data *bp = dev->priv;
+																					    int i;
+																					    struct sk_buff *skb;
+																					    unsigned long flags;
+    
+																					    save_flags(flags); cli();
+																					    while (1) {
+																						    i = bp->tx_fill + 1;
+																						    if (i >= N_TX_RING) i = 0;
+																						    if (i == bp->tx_empty) break;
+																						    skb = skb_dequeue(bp->queue);
+																						    if (skb == NULL) break;
+																						    bmac_transmit_packet(skb, dev);
+																					    }
+																					    restore_flags(flags);
+																				    }
+
+																					    static int
+																					    bmac_output(struct sk_buff *skb, struct device *dev)
+																					    {
+																						    struct bmac_data *bp = dev->priv;
+																						    skb_queue_tail(bp->queue, skb);
+																						    bmac_start(dev);
+																						    return 0;
+																					    }
+
+																						    static void bmac_tx_timeout(unsigned long data)
+																						    {
+																							    struct device *dev = (struct device *) data;
+																							    struct bmac_data *bp = (struct bmac_data *) dev->priv;
+																							    volatile struct dbdma_regs *td = bp->tx_dma;
+																							    volatile struct dbdma_regs *rd = bp->rx_dma;
+																							    volatile struct dbdma_cmd *cp;
+																							    unsigned long flags;
+																							    unsigned short config, oldConfig;
+																							    int i;
+
+																							    XXDEBUG(("bmac: tx_timeout called\n"));
+																							    save_flags(flags); cli();
+																							    bp->timeout_active = 0;
+
+																							    /* update various counters */
+/*     bmac_handle_misc_intrs(bp, 0); */
+
+																							    cp = &bp->tx_cmds[bp->tx_empty];
+/*     XXDEBUG((KERN_DEBUG "bmac: tx dmastat=%x %x runt=%d pr=%x fs=%x fc=%x\n", */
+/* 	   ld_le32(&td->status), ld_le16(&cp->xfer_status), bp->tx_bad_runt, */
+/* 	   mb->pr, mb->xmtfs, mb->fifofc)); */
+
+																							    /* turn off both tx and rx and reset the chip */
+																							    config = bmread(dev, RXCFG);
+																							    bmwrite(dev, RXCFG, (config & ~RxMACEnable));
+																							    config = bmread(dev, TXCFG);
+																							    bmwrite(dev, TXCFG, (config & ~TxMACEnable));
+																							    out_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD));
+																							    printk(KERN_ERR "bmac: transmit timeout - resetting\n");
+																							    bmac_reset_chip(dev);
+
+																							    /* restart rx dma */
+																							    cp = bus_to_virt(ld_le32(&rd->cmdptr));
+																							    out_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD));
+																							    out_le16(&cp->xfer_status, 0);
+																							    out_le32(&rd->cmdptr, virt_to_bus(cp));
+																							    out_le32(&rd->control, DBDMA_SET(RUN|WAKE));
+
+																							    /* fix up the transmit side */
+																							    XXDEBUG((KERN_DEBUG "bmac: tx empty=%d fill=%d fullup=%d\n",
+																								     bp->tx_empty, bp->tx_fill, bp->tx_fullup));
+																							    i = bp->tx_empty;
+																							    ++bp->stats.tx_errors;
+																							    if (i != bp->tx_fill) {
+																								    dev_kfree_skb(bp->tx_bufs[i]);
+																								    bp->tx_bufs[i] = NULL;
+																								    if (++i >= N_TX_RING) i = 0;
+																								    bp->tx_empty = i;
+																							    }
+																							    bp->tx_fullup = 0;
+																							    dev->tbusy = 0;
+																							    mark_bh(NET_BH);
+																							    XXDEBUG((KERN_DEBUG "bmac: clearing tbusy\n"));
+																							    if (i != bp->tx_fill) {
+																								    cp = &bp->tx_cmds[i];
+																								    out_le16(&cp->xfer_status, 0);
+																								    out_le16(&cp->command, OUTPUT_LAST);
+																								    out_le32(&td->cmdptr, virt_to_bus(cp));
+																								    out_le32(&td->control, DBDMA_SET(RUN));
+/* 	bmac_set_timeout(dev); */
+																								    XXDEBUG((KERN_DEBUG "bmac: starting %d\n", i));
+																							    }
+
+																							    /* turn it back on */
+																							    oldConfig = bmread(dev, RXCFG);		
+																							    bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); 
+																							    oldConfig = bmread(dev, TXCFG);		
+																							    bmwrite(dev, TXCFG, oldConfig | TxMACEnable );  
+
+																							    restore_flags(flags);
+																						    }
+
+#if 0
+																							    static void dump_dbdma(volatile struct dbdma_cmd *cp,int count)
+																							    {
+																								    int i,*ip;
+	
+																								    for (i=0;i< count;i++)
+																								    {
+																									    ip = (int*)(cp+i);
+	
+																									    printk("dbdma req 0x%x addr 0x%x baddr 0x%x xfer/res 0x%x\n",
+																										   ld_le32(ip+0),
+																										   ld_le32(ip+1),
+																										   ld_le32(ip+2),
+																										   ld_le32(ip+3));
+																								    }
+
+																							    }
+#endif
+
+																								    static int
+																								    bmac_proc_info ( char *buffer, char **start, off_t offset, int length, int dummy)
+																								    {
+																									    int len = 0;
+																									    off_t pos   = 0;
+																									    off_t begin = 0;
+																									    int i;
+
+																									    if (bmac_devs == NULL) return (-ENOSYS);
+
+																									    len += sprintf(buffer, "BMAC counters & registers\n");
+
+																									    for (i = 0; i<N_REG_ENTRIES; i++) {
+																										    len += sprintf(buffer + len, "%s: %#08x\n",
+																												   reg_entries[i].name,
+																												   bmread(bmac_devs, reg_entries[i].reg_offset));
+																										    pos = begin + len;
+    
+																										    if (pos < offset) {
+																											    len = 0;
+																											    begin = pos;
+																										    }
+    
+																										    if (pos > offset+length) break;
+																									    }
+  
+																									    *start = buffer + (offset - begin);
+																									    len -= (offset - begin);
+  
+																									    if (len > length) len = length;
+  
+																									    return len;
+																								    }
diff -u --recursive --new-file v2.1.111/linux/drivers/net/bmac.h linux/drivers/net/bmac.h
--- v2.1.111/linux/drivers/net/bmac.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/bmac.h	Sun Jul 26 23:35:56 1998
@@ -0,0 +1,164 @@
+/*
+ * mace.h - definitions for the registers in the "Big Mac"
+ *  Ethernet controller found in PowerMac G3 models.
+ *
+ * Copyright (C) 1998 Randy Gobbel.
+ *
+ * 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.
+ */
+
+/* The "Big MAC" appears to have some parts in common with the Sun "Happy Meal"
+ * (HME) controller.  See sunhme.h
+ */
+
+ 
+/* register offsets */
+
+/* global status and control */
+#define	XIFC		0x000   /* low-level interface control */
+#	define	TxOutputEnable	0x0001 /* output driver enable */
+#	define	XIFLoopback	0x0002 /* Loopback-mode XIF enable */
+#	define	MIILoopback	0x0004 /* Loopback-mode MII enable */
+#	define	MIILoopbackBits	0x0006
+#	define	MIIBuffDisable	0x0008 /* MII receive buffer disable */
+#	define	SQETestEnable	0x0010 /* SQE test enable */
+#	define	SQETimeWindow	0x03e0 /* SQE time window */
+#	define	XIFLanceMode	0x0010 /* Lance mode enable */
+#	define	XIFLanceIPG0	0x03e0 /* Lance mode IPG0 */
+#define	TXFIFOCSR	0x100   /* transmit FIFO control */
+#	define	TxFIFOEnable	0x0001
+#define	TXTH		0x110   /* transmit threshold */
+#	define	TxThreshold	0x0004
+#define RXFIFOCSR	0x120   /* receive FIFO control */
+#	define	RxFIFOEnable	0x0001
+#define MEMADD		0x130   /* memory address, unknown function */
+#define MEMDATAHI	0x140   /* memory data high, presently unused in driver */
+#define MEMDATALO	0x150   /* memory data low, presently unused in driver */
+#define XCVRIF		0x160   /* transceiver interface control */
+#	define	COLActiveLow	0x0002
+#	define	SerialMode	0x0004
+#	define	ClkBit		0x0008
+#	define	LinkStatus	0x0100
+#define CHIPID          0x170   /* chip ID */
+#define	MIFCSR		0x180   /* ??? */
+#define	SROMCSR		0x190   /* SROM control */
+#	define	ChipSelect	0x0001
+#	define	Clk		0x0002
+#define TXPNTR		0x1a0   /* transmit pointer */
+#define	RXPNTR		0x1b0   /* receive pointer */
+#define	STATUS		0x200   /* status--reading this clears it */
+#define	INTDISABLE	0x210   /* interrupt enable/disable control */
+/* bits below are the same in both STATUS and INTDISABLE registers */
+#	define	FrameReceived	0x00000001 /* Received a frame */
+#	define	RxFrameCntExp	0x00000002 /* Receive frame counter expired */
+#	define	RxAlignCntExp	0x00000004 /* Align-error counter expired */
+#	define	RxCRCCntExp	0x00000008 /* CRC-error counter expired */
+#	define	RxLenCntExp	0x00000010 /* Length-error counter expired */
+#	define	RxOverFlow	0x00000020 /* Receive FIFO overflow */
+#	define	RxCodeViolation	0x00000040 /* Code-violation counter expired */
+#	define	SQETestError	0x00000080 /* Test error in XIF for SQE */
+#	define	FrameSent	0x00000100 /* Transmitted a frame */
+#	define	TxUnderrun	0x00000200 /* Transmit FIFO underrun */
+#	define	TxMaxSizeError	0x00000400 /* Max-packet size error */
+#	define	TxNormalCollExp	0x00000800 /* Normal-collision counter expired */
+#	define	TxExcessCollExp	0x00001000 /* Excess-collision counter expired */
+#	define	TxLateCollExp	0x00002000 /* Late-collision counter expired */
+#	define	TxNetworkCollExp 0x00004000 /* First-collision counter expired */
+#	define	TxDeferTimerExp	0x00008000 /* Defer-timer expired */
+#	define	RxFIFOToHost	0x00010000 /* Data moved from FIFO to host */
+#	define	RxNoDescriptors	0x00020000 /* No more receive descriptors */
+#	define	RxDMAError	0x00040000 /* Error during receive DMA */
+#	define	RxDMALateErr	0x00080000 /* Receive DMA, data late */
+#	define	RxParityErr	0x00100000 /* Parity error during receive DMA */
+#	define	RxTagError	0x00200000 /* Tag error during receive DMA */
+#	define	TxEOPError	0x00400000 /* Tx descriptor did not have EOP set */
+#	define	MIFIntrEvent	0x00800000 /* MIF is signaling an interrupt */
+#	define	TxHostToFIFO	0x01000000 /* Data moved from host to FIFO  */
+#	define	TxFIFOAllSent	0x02000000 /* Transmitted all packets in FIFO */
+#	define	TxDMAError	0x04000000 /* Error during transmit DMA */
+#	define	TxDMALateError	0x08000000 /* Late error during transmit DMA */
+#	define	TxParityError	0x10000000 /* Parity error during transmit DMA */
+#	define	TxTagError	0x20000000 /* Tag error during transmit DMA */
+#	define	PIOError	0x40000000 /* PIO access got an error */
+#	define	PIOParityError	0x80000000 /* PIO access got a parity error  */
+#	define	DisableAll	0xffffffff
+#	define	EnableAll	0x00000000
+/* #	define	NormalIntEvents	~(FrameReceived | FrameSent | TxUnderrun) */
+#	define	EnableNormal	~(FrameReceived | FrameSent)
+#	define	EnableErrors	(FrameReceived | FrameSent)
+#	define	RxErrorMask	(RxFrameCntExp | RxAlignCntExp | RxCRCCntExp | \
+				 RxLenCntExp | RxOverFlow | RxCodeViolation)
+#	define	TxErrorMask	(TxUnderrun | TxMaxSizeError | TxExcessCollExp | \
+				 TxLateCollExp | TxNetworkCollExp | TxDeferTimerExp)
+
+/* transmit control */
+#define	TXRST		0x420   /* transmit reset */
+#	define	TxResetBit	0x0001
+#define	TXCFG		0x430   /* transmit configuration control*/
+#	define	TxMACEnable	0x0001 /* output driver enable */
+#	define	TxSlowMode	0x0020 /* enable slow mode */
+#	define	TxIgnoreColl	0x0040 /* ignore transmit collisions */
+#	define	TxNoFCS		0x0080 /* do not emit FCS */
+#	define	TxNoBackoff	0x0100 /* no backoff in case of collisions */
+#	define	TxFullDuplex	0x0200 /* enable full-duplex */
+#	define	TxNeverGiveUp	0x0400 /* don't give up on transmits */
+#define IPG1		0x440   /* Inter-packet gap 1 */
+#define IPG2		0x450   /* Inter-packet gap 2 */
+#define ALIMIT		0x460   /* Transmit attempt limit */
+#define SLOT		0x470   /* Transmit slot time */
+#define PALEN		0x480   /* Size of transmit preamble */
+#define PAPAT		0x490   /* Pattern for transmit preamble */
+#define TXSFD		0x4a0   /* Transmit frame delimiter */
+#define JAM		0x4b0   /* Jam size */
+#define TXMAX		0x4c0   /* Transmit max pkt size */
+#define TXMIN		0x4d0   /* Transmit min pkt size */
+#define PAREG		0x4e0   /* Count of transmit peak attempts */
+#define DCNT		0x4f0   /* Transmit defer timer */
+#define NCCNT		0x500   /* Transmit normal-collision counter */
+#define NTCNT		0x510   /* Transmit first-collision counter */
+#define EXCNT		0x520   /* Transmit excess-collision counter */
+#define LTCNT		0x530   /* Transmit late-collision counter */
+#define RSEED		0x540   /* Transmit random number seed */
+#define TXSM		0x550   /* Transmit state machine */
+
+/* receive control */
+#define RXRST		0x620   /* receive reset */
+#	define	RxResetValue	0x0000
+#define RXCFG		0x630   /* receive configuration control */
+#	define	RxMACEnable	0x0001 /* receiver overall enable */
+#	define	RxCFGReserved	0x0004
+#	define	RxPadStripEnab	0x0020 /* enable pad byte stripping */
+#	define	RxPromiscEnable	0x0040 /* turn on promiscuous mode */
+#	define	RxNoErrCheck	0x0080 /* disable receive error checking */
+#	define	RxCRCNoStrip	0x0100 /* disable auto-CRC-stripping */
+#	define	RxRejectOwnPackets 0x0200 /* don't receive our own packets */
+#	define	RxGrpPromisck	0x0400 /* enable group promiscuous mode */
+#	define	RxHashFilterEnable 0x0800 /* enable hash filter */
+#	define	RxAddrFilterEnable 0x1000 /* enable address filter */
+#define RXMAX		0x640   /* Max receive packet size */
+#define RXMIN		0x650   /* Min receive packet size */
+#define MADD2		0x660   /* our enet address, high part */
+#define MADD1		0x670   /* our enet address, middle part */
+#define MADD0		0x680   /* our enet address, low part */
+#define FRCNT		0x690   /* receive frame counter */
+#define LECNT		0x6a0   /* Receive excess length error counter */
+#define AECNT		0x6b0   /* Receive misaligned error counter */
+#define FECNT		0x6c0   /* Receive CRC error counter */
+#define RXSM		0x6d0   /* Receive state machine */
+#define RXCV		0x6e0   /* Receive code violation */
+
+#define BHASH3		0x700   /* multicast hash register */
+#define BHASH2		0x710   /* multicast hash register */
+#define BHASH1		0x720   /* multicast hash register */
+#define BHASH0		0x730   /* multicast hash register */
+
+#define AFR2		0x740   /* address filtering setup? */
+#define AFR1		0x750   /* address filtering setup? */
+#define AFR0		0x760   /* address filtering setup? */
+#define AFCR		0x770   /* address filter compare register? */
+#	define	EnableAllCompares 0x0fff
+
+/* bits in XIFC */
diff -u --recursive --new-file v2.1.111/linux/drivers/net/daynaport.c linux/drivers/net/daynaport.c
--- v2.1.111/linux/drivers/net/daynaport.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/daynaport.c	Sun Jul 26 23:35:56 1998
@@ -0,0 +1,603 @@
+/* mac_ns8390.c: A Macintosh 8390 based ethernet driver for linux. */
+/*
+	Derived from code:
+	
+	Written 1993-94 by Donald Becker.
+
+	Copyright 1993 United States Government as represented by the
+	Director, National Security Agency.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+
+	    TODO:
+
+	    The block output routines may be wrong for non Dayna
+	    cards
+
+	    Reading MAC addresses
+*/
+
+static const char *version =
+	"mac_ns8390.c:v0.01 7/5/97 Alan Cox (Alan.Cox@linux.org)\n";
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/nubus.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include "8390.h"
+
+int ns8390_probe1(struct device *dev, int word16, char *name, int id, int prom);
+
+static int ns8390_open(struct device *dev);
+static void ns8390_no_reset(struct device *dev);
+static int ns8390_close_card(struct device *dev);
+
+static void interlan_reset(struct device *dev);
+
+static void dayna_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
+						int ring_page);
+static void dayna_block_input(struct device *dev, int count,
+						  struct sk_buff *skb, int ring_offset);
+static void dayna_block_output(struct device *dev, int count,
+							const unsigned char *buf, const start_page);
+
+static void sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
+						int ring_page);
+static void sane_block_input(struct device *dev, int count,
+						  struct sk_buff *skb, int ring_offset);
+static void sane_block_output(struct device *dev, int count,
+							const unsigned char *buf, const start_page);
+
+
+#define WD_START_PG	0x00	/* First page of TX buffer */
+#define WD03_STOP_PG	0x20	/* Last page +1 of RX ring */
+#define WD13_STOP_PG	0x40	/* Last page +1 of RX ring */
+
+
+#define DAYNA_MAC_BASE		0xf0007
+#define DAYNA_8390_BASE		0x80000 /* 3 */
+#define DAYNA_8390_MEM		0x00000
+#define DAYNA_MEMSIZE		0x04000	/* First word of each long ! */
+
+#define APPLE_8390_BASE		0xE0000
+#define APPLE_8390_MEM		0xD0000
+#define APPLE_MEMSIZE		8192    /* FIXME: need to dynamically check */
+
+#define KINETICS_8390_BASE	0x80003
+#define KINETICS_8390_MEM	0x00000
+#define KINETICS_MEMSIZE	8192    /* FIXME: need to dynamically check */
+
+static int test_8390(volatile char *ptr, int scale)
+{
+	int regd;
+	int v;
+	
+	if(nubus_hwreg_present(&ptr[0x00])==0)
+		return -EIO;
+	if(nubus_hwreg_present(&ptr[0x0D<<scale])==0)
+		return -EIO;
+	if(nubus_hwreg_present(&ptr[0x0D<<scale])==0)
+		return -EIO;
+	ptr[0x00]=E8390_NODMA+E8390_PAGE1+E8390_STOP;
+	regd=ptr[0x0D<<scale];
+	ptr[0x0D<<scale]=0xFF;
+	ptr[0x00]=E8390_NODMA+E8390_PAGE0;
+	v=ptr[0x0D<<scale];
+	if(ptr[0x0D<<scale]!=0)
+	{
+		ptr[0x0D<<scale]=regd;
+		return -ENODEV;
+	}
+/*	printk("NS8390 found at %p scaled %d\n", ptr,scale);*/
+	return 0;
+}
+/*
+ *    Identify the species of NS8390 card/driver we need
+ */
+
+#define NS8390_DAYNA		1
+#define NS8390_INTERLAN		2
+#define NS8390_KINETICS		3
+#define NS8390_APPLE		4
+#define NS8390_FARALLON		5
+#define NS8390_ASANTE		6
+
+int ns8390_ident(struct nubus_type *nb)
+{
+	/* It appears anything with a software type of 0 is an apple
+	   compatible - even if the hardware matches others */
+	   
+	if(nb->DrSW==0x0001 || nb->DrSW==0x0109 || nb->DrSW==0x0000 || nb->DrSW==0x0100)
+		return NS8390_APPLE;
+	
+	/* Dayna ex Kinetics board */
+	if(nb->DrHW==0x0103)
+		return NS8390_DAYNA;
+
+	/* Asante board */
+	if(nb->DrHW==0x0104)
+		return NS8390_ASANTE;
+	if(nb->DrHW==0x0100)
+		return NS8390_INTERLAN;
+	if(nb->DrHW==0x0106)
+		return NS8390_KINETICS;
+	if(nb->DrSW==0x010C)
+		return NS8390_FARALLON;
+	return -1;
+}
+
+/*
+ *    Probe for 8390 cards.  
+ *    The ns8390_probe1() routine initializes the card and fills the
+ *    station address field. On entry base_addr is set, irq is set
+ *    (These come from the nubus probe code). dev->mem_start points
+ *    at the memory ring, dev->mem_end gives the end of it.
+ */
+
+int ns8390_probe(struct nubus_device_specifier *d, int slot, struct nubus_type *match)
+{
+	struct device *dev;
+	volatile unsigned short *i;
+	volatile unsigned char *p;
+	int plen;
+	int id;
+
+	if(match->category!=NUBUS_CAT_NETWORK || match->type!=1)
+		return -ENODEV;		
+	/* Ok so it is an ethernet network device */
+	if((id=ns8390_ident(match))==-1)
+	{
+		printk("Ethernet but type unknown %d\n",match->DrHW);
+		return -ENODEV;
+	}
+	dev = init_etherdev(0, 0);
+	if(dev==NULL)
+		return -ENOMEM;
+
+	/*
+	 *	Dayna specific init
+	 */
+	if(id==NS8390_DAYNA)
+	{
+		dev->base_addr=(int)(nubus_slot_addr(slot)+DAYNA_8390_BASE);
+		dev->mem_start=(int)(nubus_slot_addr(slot)+DAYNA_8390_MEM);
+		dev->mem_end=dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */
+	
+		printk("daynaport: testing board: ");
+
+		printk("memory - ");	
+	
+		i=(void *)dev->mem_start;
+		memset((void *)i,0xAA, DAYNA_MEMSIZE);
+		while(i<(volatile unsigned short *)dev->mem_end)
+		{
+			if(*i!=0xAAAA)
+				goto membad;
+			*i=0x5555;
+			if(*i!=0x5555)
+				goto membad;
+			i+=2;	/* Skip a word */
+		}
+
+		printk("controller - ");
+	
+		p=(void *)dev->base_addr;
+		plen=0;
+	
+		while(plen<0x3FF00)
+		{
+			if(test_8390(p,0)==0)
+				break;
+			if(test_8390(p,1)==0)
+				break;
+			if(test_8390(p,2)==0)
+				break;
+			if(test_8390(p,3)==0)
+				break;
+			plen++;
+			p++;
+		}
+		if(plen==0x3FF00)
+			goto membad;
+		printk("OK\n");
+		dev->irq=slot;
+		if(ns8390_probe1(dev, 0, "dayna", id, -1)==0)
+		return 0;
+	}
+	/* Apple, Farallon, Asante */
+	if(id==NS8390_APPLE|| id==NS8390_FARALLON || id==NS8390_ASANTE)
+	{
+		dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE);
+		dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM);
+		dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */
+		dev->irq=slot;
+		printk("apple/clone: testing board: ");
+
+		printk("memory - ");		
+
+		i=(void *)dev->mem_start;
+		memset((void *)i,0xAA, DAYNA_MEMSIZE);
+		while(i<(volatile unsigned short *)dev->mem_end)
+		{
+			if(*i!=0xAAAA)
+				goto membad;
+			*i=0x5555;
+			if(*i!=0x5555)
+				goto membad;
+			i+=2;	/* Skip a word */
+		}
+		printk("OK\n");
+
+		if(id==NS8390_FARALLON)
+		{
+			if(ns8390_probe1(dev, 1, "farallon", id, -1)==0)
+				return 0;
+		}
+		else
+		{
+			if(ns8390_probe1(dev, 1, "apple/clone", id, -1)==0)
+			    return 0;
+		}
+	}
+	/* Interlan */
+	if(id==NS8390_INTERLAN)
+	{
+		/* As apple and asante */
+		dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE);
+		dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM);
+		dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */
+		dev->irq=slot;
+		if(ns8390_probe1(dev, 1, "interlan", id, -1)==0)
+			return 0;
+	}
+	/* Kinetics */
+	if(id==NS8390_KINETICS)
+	{
+		dev->base_addr=(int)(nubus_slot_addr(slot)+KINETICS_8390_BASE);
+		dev->mem_start=(int)(nubus_slot_addr(slot)+KINETICS_8390_MEM);
+		dev->mem_end=dev->mem_start+KINETICS_MEMSIZE; /* 8K it seems */
+		dev->irq=slot;
+		if(ns8390_probe1(dev, 0, "kinetics", id, -1)==0)
+			return 0;
+	}
+	kfree(dev);
+	return -ENODEV;
+membad:
+	printk("failed.\n");
+	kfree(dev);
+	return -ENODEV;
+}
+
+int ns8390_probe1(struct device *dev, int word16, char *model_name, int type, int promoff)
+{
+	static unsigned version_printed = 0;
+
+	static unsigned char fwrd4_offsets[16]={
+		0,      4,      8,      12,
+		16,     20,     24,     28,
+		32,     36,     40,     44,
+		48,     52,     56,     60
+	};
+	static unsigned char back4_offsets[16]={
+		60,     56,     52,     48,
+		44,     40,     36,     32,
+		28,     24,     20,     16,
+		12,     8,      4,      0
+	};
+
+	unsigned char *prom=((unsigned char *)nubus_slot_addr(dev->irq))+promoff;
+
+	if (ei_debug  &&  version_printed++ == 0)
+		printk(version);
+	
+	/* Snarf the interrupt now.  There's no point in waiting since we cannot
+	   share a slot! and the board will usually be enabled. */
+	if (nubus_request_irq(dev->irq, dev, ei_interrupt)) 
+	{
+		printk (" unable to get nubus IRQ %d.\n", dev->irq);
+		return EAGAIN;
+	}
+	
+	/* Allocate dev->priv and fill in 8390 specific dev fields. */
+	if (ethdev_init(dev)) 
+	{	
+		printk (" unable to get memory for dev->priv.\n");
+		nubus_free_irq(dev->irq);
+		return -ENOMEM;
+	}
+
+	/* OK, we are certain this is going to work.  Setup the device. */
+
+	ei_status.name = model_name;
+	ei_status.word16 = word16;
+	ei_status.tx_start_page = WD_START_PG;
+	ei_status.rx_start_page = WD_START_PG + TX_PAGES;
+
+	dev->rmem_start = dev->mem_start + TX_PAGES*256;
+	ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
+	dev->rmem_end = dev->mem_end;
+	
+	if(promoff==-1)		/* Use nubus resources ? */
+	{
+		if(nubus_ethernet_addr(dev->irq /* slot */, dev->dev_addr))
+		{
+		  printk("mac_ns8390: MAC address not in resources!\n");
+		  return -ENODEV;
+		}
+	}
+	else			/* Pull it off the card */
+	{
+		int i=0;
+		int x=1;
+		/* These should go in the end I hope */
+		if(type==NS8390_DAYNA)
+			x=2;
+		if(type==NS8390_INTERLAN)
+			x=4;
+		while(i<6)
+		{
+			dev->dev_addr[i]=*prom;
+			prom+=x;
+			if(i)
+				printk(":");
+			printk("%02X",dev->dev_addr[i++]);
+		}
+	}
+
+	printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
+		   model_name, dev->irq, dev->mem_start, dev->mem_end-1);
+
+	switch(type)
+	{
+		case NS8390_DAYNA:      /* Dayna card */
+			/* 16 bit, 4 word offsets */
+			ei_status.reset_8390 = &ns8390_no_reset;
+			ei_status.block_input = &dayna_block_input;
+			ei_status.block_output = &dayna_block_output;
+			ei_status.get_8390_hdr = &dayna_get_8390_hdr;
+			ei_status.reg_offset = fwrd4_offsets;
+			break;
+		case NS8390_APPLE:	/* Apple/Asante/Farallon */
+		case NS8390_FARALLON:
+		case NS8390_ASANTE:
+			/*      16 bit card, register map is reversed */
+			ei_status.reset_8390 = &ns8390_no_reset;
+			ei_status.block_input = &sane_block_input;
+			ei_status.block_output = &sane_block_output;
+			ei_status.get_8390_hdr = &sane_get_8390_hdr;
+			ei_status.reg_offset = back4_offsets;
+			break;
+		case NS8390_INTERLAN:   /* Interlan */
+			/*      16 bit card, map is forward */
+			ei_status.reset_8390 = &interlan_reset;
+			ei_status.block_input = &sane_block_input;
+			ei_status.block_output = &sane_block_output;
+			ei_status.get_8390_hdr = &sane_get_8390_hdr;
+			ei_status.reg_offset = back4_offsets;
+			break;
+		case NS8390_KINETICS:   /* Kinetics */
+			/*      8bit card, map is forward */
+			ei_status.reset_8390 = &ns8390_no_reset;
+			ei_status.block_input = &sane_block_input;
+			ei_status.block_output = &sane_block_output;
+			ei_status.get_8390_hdr = &sane_get_8390_hdr;
+			ei_status.reg_offset = back4_offsets;
+			break;
+		default:
+			panic("Detected a card I can't drive - whoops\n");
+	}
+	dev->open = &ns8390_open;
+	dev->stop = &ns8390_close_card;
+
+	NS8390_init(dev, 0);
+
+	return 0;
+}
+
+static int ns8390_open(struct device *dev)
+{
+	ei_open(dev);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static void ns8390_no_reset(struct device *dev)
+{
+	if (ei_debug > 1) 
+		printk("Need to reset the NS8390 t=%lu...", jiffies);
+	ei_status.txing = 0;
+	if (ei_debug > 1) printk("reset not supported\n");
+	return;
+}
+
+static int ns8390_close_card(struct device *dev)
+{
+	if (ei_debug > 1)
+		printk("%s: Shutting down ethercard.\n", dev->name);
+	ei_close(dev);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+struct nubus_device_specifier nubus_8390={
+	ns8390_probe,
+	NULL
+};
+
+
+/*
+ *    Interlan Specific Code Starts Here
+ */
+
+static void interlan_reset(struct device *dev)
+{
+	unsigned char *target=nubus_slot_addr(dev->irq);
+	if (ei_debug > 1) 
+	printk("Need to reset the NS8390 t=%lu...", jiffies);
+	ei_status.txing = 0;
+	/* This write resets the card */
+	target[0xC0000]=0;
+	if (ei_debug > 1) printk("reset complete\n");
+	return;
+}
+
+/*
+ *    Daynaport code (some is used by other drivers)
+ */
+
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+   we don't need to be concerned with ring wrap as the header will be at
+   the start of a page, so we optimize accordingly. */
+
+
+/* Block input and output are easy on shared memory ethercards, and trivial
+   on the Daynaport card where there is no choice of how to do it.
+   The only complications are that the ring buffer wraps.
+*/
+
+static void dayna_cpu_memcpy(struct device *dev, void *to, int from, int count)
+{
+	volatile unsigned short *ptr;
+	unsigned short *target=to;
+	from<<=1;	/* word, skip overhead */
+	ptr=(unsigned short *)(dev->mem_start+from);
+	while(count>=2)
+	{
+		*target++=*ptr++;	/* Copy and */
+		ptr++;			/* Cruft and */
+		count-=2;
+	}
+	/*
+	 *	Trailing byte ?
+	 */
+	if(count)
+	{
+		/* Big endian */
+		unsigned short v=*ptr;
+		*((char *)target)=v>>8;
+	}
+}
+
+static void cpu_dayna_memcpy(struct device *dev, int to, const void *from, int count)
+{
+	volatile unsigned short *ptr;
+	const unsigned short *src=from;
+	to<<=1;	/* word, skip overhead */
+	ptr=(unsigned short *)(dev->mem_start+to);
+	while(count>=2)
+	{
+		*ptr++=*src++;		/* Copy and */
+		ptr++;			/* Cruft and */
+		count-=2;
+	}
+	/*
+	 *	Trailing byte ?
+	 */
+	if(count)
+	{
+		/* Big endian */
+		unsigned short v=*src;
+		*((char *)ptr)=v>>8;
+	}
+}
+
+static void dayna_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
+	dayna_cpu_memcpy(dev, (void *)hdr, hdr_start, 4);
+	/* Register endianism - fix here rather than 8390.c */
+	hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
+}
+
+static void dayna_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+	unsigned long xfer_start = xfer_base+dev->mem_start;
+
+	/*
+	 *	Note the offset maths is done in card memory space which
+	 *	is word per long onto our space.
+	 */
+	 
+	if (xfer_start + count > dev->rmem_end) 
+	{
+		/* We must wrap the input move. */
+		int semi_count = dev->rmem_end - xfer_start;
+		dayna_cpu_memcpy(dev, skb->data, xfer_base, semi_count);
+		count -= semi_count;
+		dayna_cpu_memcpy(dev, skb->data + semi_count, 
+			dev->rmem_start - dev->mem_start, count);
+	}
+	else
+	{
+		dayna_cpu_memcpy(dev, skb->data, xfer_base, count);
+	}
+}
+
+static void dayna_block_output(struct device *dev, int count, const unsigned char *buf,
+				int start_page)
+{
+	long shmem = (start_page - WD_START_PG)<<8;
+	
+	cpu_dayna_memcpy(dev, shmem, buf, count);
+}
+
+/*
+ *	Cards with full width memory
+ */
+
+
+static void sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
+	memcpy((void *)hdr, (char *)dev->mem_start+hdr_start, 4);
+	/* Register endianism - fix here rather than 8390.c */
+	hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
+}
+
+static void sane_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+	unsigned long xfer_start = xfer_base+dev->mem_start;
+
+	if (xfer_start + count > dev->rmem_end) 
+	{
+		/* We must wrap the input move. */
+		int semi_count = dev->rmem_end - xfer_start;
+		memcpy(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
+		count -= semi_count;
+		memcpy(skb->data + semi_count, 
+			(char *)dev->rmem_start, count);
+	}
+	else
+	{
+		memcpy(skb->data, (char *)dev->mem_start+xfer_base, count);
+	}
+}
+
+static void sane_block_output(struct device *dev, int count, const unsigned char *buf,
+				int start_page)
+{
+	long shmem = (start_page - WD_START_PG)<<8;
+	
+	memcpy((char *)dev->mem_start+shmem, buf, count);
+}
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c daynaport.c"
+ *  version-control: t
+ *  tab-width: 4
+ *  kept-new-versions: 5
+ * End:
+ */
diff -u --recursive --new-file v2.1.111/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
--- v2.1.111/linux/drivers/net/eepro.c	Thu Feb 12 20:56:08 1998
+++ linux/drivers/net/eepro.c	Sun Jul 26 23:35:56 1998
@@ -1106,6 +1106,8 @@
 			dev->tbusy = 0;
 		}
 
+		lp->stats.tx_bytes += length;
+
 		if (net_debug > 5)
 			printk("eepro: exiting hardware_send_packet routine.\n");
 		return;
@@ -1164,6 +1166,7 @@
 			skb->protocol = eth_type_trans(skb,dev);
 			netif_rx(skb);
 			lp->stats.rx_packets++;
+			lp->stats.rx_bytes += rcv_size;
 		}
 		else { /* Not sure will ever reach here,
 			  I set the 595 to discard bad received frames */
diff -u --recursive --new-file v2.1.111/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.1.111/linux/drivers/net/eepro100.c	Tue Jul 21 00:15:31 1998
+++ linux/drivers/net/eepro100.c	Mon Jul 27 14:42:45 1998
@@ -1,13 +1,13 @@
 /* drivers/net/eepro100.c: An Intel i82557 Ethernet driver for Linux. */
 /*
    NOTICE: this version tested with kernels 1.3.72 and later only!
-	Written 1996-1997 by Donald Becker.
+	Written 1996-1998 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
 
 	This driver is for the Intel EtherExpress Pro 100B boards.
-	It should work with other i82557 boards (if any others exist).
+	It should work with other i82557 and i82558 boards.
 	To use a built-in driver, install as drivers/net/eepro100.c.
 	To use as a module, use the compile-command at the end of the file.
 
@@ -15,11 +15,13 @@
 	Center of Excellence in Space Data and Information Sciences
 	   Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771
 	For updates see
-	<base href="http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html">
+		http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html
+	There is also a mailing list based at
+		linux-eepro100@cesdis.gsfc.nasa.gov
 */
 
 static const char *version =
-"eepro100.c:v0.36 10/20/97 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov\n";
+"eepro100.c:v1.02 7/24/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n";
 
 /* A few user-configurable values that apply to all boards.
    First set are undocumented and spelled per Intel recommendations. */
@@ -33,36 +35,15 @@
 
 /* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
    Lower values use more memory, but are faster. */
-/*
- * NOTE! The value of 2000 means that this optimization never gets
- * used. Rationale: it seems to be broken when in low-memory situations,
- * apparently when alloc_skb() can return NULL the clever list of
- * copy-buffers can get buggered. 
- *
- * My personal suspicion is that the allocation failure will cause
- * us to not remove the skb from the list of available buffers, but
- * we'd already have done a "skb_push()" with the data we got, so
- * the buffer stays on the list but the available memory in it
- * shrinks until we panic.
- *
- * Donald, when you fix this you can shrink this value again.
- *
- *		Linus
- */
-static int rx_copybreak = 2000;
+static int rx_copybreak = 200;
 
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 200;
+static int max_interrupt_work = 20;
+
+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
+static int multicast_filter_limit = 64;
 
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
 #include <linux/module.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
 
 #include <linux/version.h>
 #include <linux/kernel.h>
@@ -75,7 +56,6 @@
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
-#include <linux/delay.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -84,74 +64,44 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-
-/* A nominally proper method to handle version dependencies is to use
-   LINUX_VERSION_CODE in version.h, but that triggers recompiles w/'make'. */
-#define VERSION(v,p,s) (((v)<<16)+(p<<8)+s)
-#ifdef MODULE
-#if (LINUX_VERSION_CODE < VERSION(1,3,0))
-#define KERNEL_1_2
-#else /* 1.3.0 */
-#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
-#define NEW_MULTICAST
-#define LINUX_1_4
-#else
-#warning "This driver is tested for 1.3.44 and later development kernels only."
-#endif /* 1.3.44 */
-#endif
-#else
-
-#if (LINUX_VERSION_CODE >= 0x10344)
-#define NEW_MULTICAST
 #include <linux/delay.h>
-#endif
 
-#ifdef HAVE_HEADER_CACHE
-#define LINUX_1_4
-#define NEW_MULTICAST
-#else
-#ifdef ETH_P_DDCMP				/* Warning: Bogus!  This means IS_LINUX_1_3. */
-#define KERNEL_1_3
-#else
-#define KERNEL_1_2
-#endif
+/* Unused in the 2.0.* version, but retained for documentation. */
+#if LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Intel i82557/i82558 EtherExpressPro driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(congenb, "i");
+MODULE_PARM(txfifo, "i");
+MODULE_PARM(rxfifo, "i");
+MODULE_PARM(txdmacount, "i");
+MODULE_PARM(rxdmacount, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(multicast_filter_limit, "i");
 #endif
 
-#endif
-/* This should be in a header file. */
-#if (LINUX_VERSION_CODE < VERSION(1,3,44))
-struct device *init_etherdev(struct device *dev, int sizeof_priv,
-							 unsigned long *mem_startp);
-#endif
-#if LINUX_VERSION_CODE < 0x10300
-#define RUN_AT(x) (x)			/* What to put in timer->expires.  */
-#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
-#define virt_to_bus(addr)  ((unsigned long)addr)
-#define bus_to_virt(addr) ((void*)addr)
-#else  /* 1.3.0 and later */
 #define RUN_AT(x) (jiffies + (x))
-#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
-#endif
 
 #if (LINUX_VERSION_CODE < 0x20123)
 #define test_and_set_bit(val, addr) set_bit(val, addr)
-#include <linux/bios32.h>
+#endif
+#if LINUX_VERSION_CODE < 0x20159
+#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
+#else
+#define dev_free_skb(skb) dev_kfree_skb(skb);
+#endif
+#if LINUX_VERSION_CODE < 0x20155
+#define pci_present() pcibios_present()
 #endif
 
-/* The total I/O port extent of the board.  Nominally 0x18, but rounded up
-   for PCI allocation. */
+/* The total I/O port extent of the board.
+   The registers beyond 0x18 only exist on the i82558. */
 #define SPEEDO3_TOTAL_SIZE 0x20
 
-#ifdef HAVE_DEVLIST
-struct netdev_entry eepro100_drv =
-{"EEPro-100", eepro100_init, SPEEDO3_TOTAL_SIZE, NULL};
-#endif
-
-#ifdef SPEEDO3_DEBUG
-int speedo_debug = SPEEDO3_DEBUG;
-#else
-int speedo_debug = 3;
-#endif
+int speedo_debug = 1;
 
 /*
 				Theory of Operation
@@ -183,7 +133,7 @@
 Despite the extra space overhead in each receive skbuff, the driver must use
 the simplified Rx buffer mode to assure that only a single data buffer is
 associated with each RxFD. The driver implements this by reserving space
-for the Rx descriptor at the head of each Rx skbuff
+for the Rx descriptor at the head of each Rx skbuff.
 
 The Speedo-3 has receive and command unit base addresses that are added to
 almost all descriptor pointers.  The driver sets these to zero, so that all
@@ -198,10 +148,13 @@
 
 The driver must use the complex Tx command+descriptor mode in order to
 have a indirect pointer to the skbuff data section.  Each Tx command block
-(TxCB) is associated with a single, immediately appended Tx buffer descriptor
+(TxCB) is associated with two immediately appended Tx Buffer Descriptor
 (TxBD).  A fixed ring of these TxCB+TxBD pairs are kept as part of the
 speedo_private data structure for each adapter instance.
 
+The newer i82558 explicitly supports this structure, and can read the two
+TxBDs in the same PCI burst as the TxCB.
+
 This ring structure is used for all normal transmit packets, but the
 transmit packet descriptors aren't long enough for most non-Tx commands such
 as CmdConfigure.  This is complicated by the possibility that the chip has
@@ -290,26 +243,19 @@
 #define PKT_BUF_SZ		1536
 
 /* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  ((400*HZ)/1000)
+#define TX_TIMEOUT  ((800*HZ)/1000)
 
 /* How to wait for the command unit to accept a command.
    Typically this takes 0 ticks. */
-static inline void wait_for_cmd_done(int cmd_ioaddr)
+static inline void wait_for_cmd_done(long cmd_ioaddr)
 {
-  short wait = 100;
-  do   ;
-  while(inb(cmd_ioaddr) && --wait >= 0);
+	int wait = 100;
+	do   ;
+	while(inb(cmd_ioaddr) && --wait >= 0);
 }
 
 /* Operational parameter that usually are not changed. */
 
-#ifndef PCI_VENDOR_ID_INTEL		/* Now defined in linux/pci.h */
-#define PCI_VENDOR_ID_INTEL		0x8086 /* Hmmmm, how did they pick that? */
-#endif
-#ifndef PCI_DEVICE_ID_INTEL_82557
-#define PCI_DEVICE_ID_INTEL_82557	0x1229
-#endif
-
 /* The rest of these values should never change. */
 
 /* Offsets to the various registers.
@@ -364,17 +310,23 @@
 	u16 size;
 };
 
-/* Elements of the RxFD.status word. */
-#define RX_COMPLETE 0x8000
+/* Selected elements of the RxFD.status word. */
+enum RxFD_bits {
+	RxComplete=0x8000, RxOK=0x2000,
+	RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010,
+	RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002,
+};
 
 struct TxFD {					/* Transmit frame descriptor set. */
 	s32 status;
 	u32 link;					/* void * */
 	u32 tx_desc_addr;			/* Always points to the tx_buf_addr element. */
 	s32 count;					/* # of TBD (=1), Tx start thresh., etc. */
-	/* This constitutes a single "TBD" entry -- we only use one. */
-	u32 tx_buf_addr;			/* void *, frame to be transmitted.  */
-	s32 tx_buf_size;			/* Length of Tx frame. */
+	/* This constitutes two "TBD" entries -- we only use one. */
+	u32 tx_buf_addr0;			/* void *, frame to be transmitted.  */
+	s32 tx_buf_size0;			/* Length of Tx frame. */
+	u32 tx_buf_addr1;			/* void *, frame to be transmitted.  */
+	s32 tx_buf_size1;			/* Length of Tx frame. */
 };
 
 /* Elements of the dump_statistics block. This block must be lword aligned. */
@@ -409,9 +361,6 @@
 	/* Rx descriptor ring & addresses of receive-in-place skbuffs. */
 	struct RxFD *rx_ringp[RX_RING_SIZE];
 	struct sk_buff* rx_skbuff[RX_RING_SIZE];
-#if (LINUX_VERSION_CODE < 0x10300)	/* Kernel v1.2.*. */
-	struct RxFD saved_skhead[RX_RING_SIZE];	/* Saved skbuff header chunk. */
-#endif
 	struct RxFD *last_rxf;	/* Last command sent. */
 	struct enet_statistics stats;
 	struct speedo_stats lstats;
@@ -423,6 +372,7 @@
 	u8 config_cmd_data[22];			/* .. and setup parameters. */
 	int mc_setup_frm_len;			 	/* The length of an allocated.. */
 	struct descriptor *mc_setup_frm; 	/* ..multicast setup frame. */
+	int in_interrupt;					/* Word-aligned dev->interrupt */
 	char rx_mode;						/* Current PROMISC/ALLMULTI setting. */
 	unsigned int tx_full:1;				/* The Tx queue is full. */
 	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
@@ -436,11 +386,16 @@
 /* The parameters for a CmdConfigure operation.
    There are so many options that it would be difficult to document each bit.
    We mostly use the default or recommended settings. */
-const char basic_config_cmd[22] = {
+const char i82557_config_cmd[22] = {
 	22, 0x08, 0, 0,  0, 0x80, 0x32, 0x03,  1, /* 1=Use MII  0=Use AUI */
 	0, 0x2E, 0,  0x60, 0,
 	0xf2, 0x48,   0, 0x40, 0xf2, 0x80, 		/* 0x40=Force full-duplex */
 	0x3f, 0x05, };
+const char i82558_config_cmd[22] = {
+	22, 0x08, 0, 1,  0, 0x80, 0x22, 0x03,  1, /* 1=Use MII  0=Use AUI */
+	0, 0x2E, 0,  0x60, 0x08, 0x88,
+	0x68, 0, 0x40, 0xf2, 0xBD, 		/* 0xBD->0xFD=Force full-duplex */
+	0x31, 0x05, };
 
 /* PHY media interface chips. */
 static const char *phys[] = {
@@ -452,12 +407,12 @@
 					 S80C24, I82555, DP83840A=10, };
 static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 };
 
-static void speedo_found1(struct device *dev, int ioaddr, int irq,
-						  int options, int card_idx);
+static void speedo_found1(struct device *dev, long ioaddr, int irq,
+						  int card_idx);
 
-static int read_eeprom(int ioaddr, int location);
-static int mdio_read(int ioaddr, int phy_id, int location);
-static int mdio_write(int ioaddr, int phy_id, int location, int value);
+static int read_eeprom(long ioaddr, int location);
+static int mdio_read(long ioaddr, int phy_id, int location);
+static int mdio_write(long ioaddr, int phy_id, int location, int value);
 static int speedo_open(struct device *dev);
 static void speedo_timer(unsigned long data);
 static void speedo_init_rx_ring(struct device *dev);
@@ -466,9 +421,7 @@
 static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
 static int speedo_close(struct device *dev);
 static struct enet_statistics *speedo_get_stats(struct device *dev);
-#ifdef HAVE_PRIVATE_IOCTL
 static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd);
-#endif
 static void set_rx_mode(struct device *dev);
 
 
@@ -477,8 +430,8 @@
 /* 'options' is used to pass a transceiver override or full-duplex flag
    e.g. "options=16" for FD, "options=32" for 100mbps-only. */
 static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-#ifdef MODULE
 static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+#ifdef MODULE
 static int debug = -1;			/* The debug level */
 #endif
 
@@ -488,98 +441,97 @@
 int eepro100_init(struct device *dev)
 {
 	int cards_found = 0;
+	static int pci_index = 0;
 
-	if (pci_present()) {
-		static int pci_index = 0;
+	if (! pci_present())
+		return cards_found;
 
-		for (; pci_index < 8; pci_index++) {
-			unsigned char pci_bus, pci_device_fn, pci_latency;
-#if (LINUX_VERSION_CODE >= VERSION(2,1,85))
-			unsigned int pci_irq_line;
-			struct pci_dev *pdev;
-#else
-			unsigned char pci_irq_line;
-#endif
-#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
-			int pci_ioaddr;
-#else
-			long pci_ioaddr;
-#endif
-			unsigned short pci_command;
-
-			if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
-						PCI_DEVICE_ID_INTEL_82557,
-						pci_index, &pci_bus,
-						&pci_device_fn))
-			  break;
-#if (LINUX_VERSION_CODE >= VERSION(2,1,85))
-			pdev = pci_find_slot(pci_bus, pci_device_fn);
-			pci_irq_line = pdev->irq;
-			pci_ioaddr = pdev->base_address[1];
+	for (; pci_index < 8; pci_index++) {
+		unsigned char pci_bus, pci_device_fn, pci_latency;
+		long ioaddr;
+		int irq;
+
+		u16 pci_command, new_command;
+
+		if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
+								PCI_DEVICE_ID_INTEL_82557,
+								pci_index, &pci_bus,
+								&pci_device_fn))
+			break;
+#if LINUX_VERSION_CODE >= 0x20155  ||  PCI_SUPPORT_1
+		{
+			struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
+			ioaddr = pdev->base_address[1];		/* Use [0] to mem-map */
+			irq = pdev->irq;
+		}
 #else
+		{
+			u32 pci_ioaddr;
+			u8 pci_irq_line;
 			pcibios_read_config_byte(pci_bus, pci_device_fn,
 									 PCI_INTERRUPT_LINE, &pci_irq_line);
 			/* Note: BASE_ADDRESS_0 is for memory-mapping the registers. */
 			pcibios_read_config_dword(pci_bus, pci_device_fn,
 									  PCI_BASE_ADDRESS_1, &pci_ioaddr);
+			ioaddr = pci_ioaddr;
+			irq = pci_irq_line;
+		}
 #endif
-			/* Remove I/O space marker in bit 0. */
-			pci_ioaddr &= ~3;
-			if (speedo_debug > 2)
-				printk("Found Intel i82557 PCI Speedo at I/O %#x, IRQ %d.\n",
-					   (int)pci_ioaddr, pci_irq_line);
-
-			/* Get and check the bus-master and latency values. */
-			pcibios_read_config_word(pci_bus, pci_device_fn,
-									 PCI_COMMAND, &pci_command);
-			if ( ! (pci_command & PCI_COMMAND_MASTER)) {
-				printk("  PCI Master Bit has not been set! Setting...\n");
-				pci_command |= PCI_COMMAND_MASTER;
-				pcibios_write_config_word(pci_bus, pci_device_fn,
-										  PCI_COMMAND, pci_command);
-			}
-			pcibios_read_config_byte(pci_bus, pci_device_fn,
-										 PCI_LATENCY_TIMER, &pci_latency);
-			if (pci_latency < 10) {
-				printk("  PCI latency timer (CFLT) is unreasonably low at %d."
-					   "  Setting to 255 clocks.\n", pci_latency);
-				pcibios_write_config_byte(pci_bus, pci_device_fn,
-										  PCI_LATENCY_TIMER, 255);
-			} else if (speedo_debug > 1)
-				printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
-
-#ifdef MODULE
-			speedo_found1(dev, pci_ioaddr, pci_irq_line, options[cards_found],
-						  cards_found);
-#else
-			speedo_found1(dev, pci_ioaddr, pci_irq_line,
-						  dev ? dev->mem_start : 0, -1);
-#endif
-			dev = NULL;
-			cards_found++;
+		/* Remove I/O space marker in bit 0. */
+		ioaddr &= ~3;
+		if (speedo_debug > 2)
+			printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
+				   ioaddr, irq);
+
+		/* Get and check the bus-master and latency values. */
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+								 PCI_COMMAND, &pci_command);
+		new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+		if (pci_command != new_command) {
+			printk(KERN_INFO "  The PCI BIOS has not enabled this"
+				   " device!  Updating PCI command %4.4x->%4.4x.\n",
+				   pci_command, new_command);
+			pcibios_write_config_word(pci_bus, pci_device_fn,
+									  PCI_COMMAND, new_command);
 		}
+		pcibios_read_config_byte(pci_bus, pci_device_fn,
+								 PCI_LATENCY_TIMER, &pci_latency);
+		if (pci_latency < 32) {
+			printk("  PCI latency timer (CFLT) is unreasonably low at %d."
+				   "  Setting to 32 clocks.\n", pci_latency);
+			pcibios_write_config_byte(pci_bus, pci_device_fn,
+									  PCI_LATENCY_TIMER, 32);
+		} else if (speedo_debug > 1)
+			printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
+
+		speedo_found1(dev, ioaddr, irq, cards_found);
+		dev = NULL;
+		cards_found++;
 	}
 
 	return cards_found;
 }
 
-static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
+static void speedo_found1(struct device *dev, long ioaddr, int irq,
 						  int card_idx)
 {
 	static int did_version = 0;			/* Already printed version info. */
 	struct speedo_private *sp;
 	char *product;
-	int i;
+	int i, option;
 	u16 eeprom[0x40];
 
 	if (speedo_debug > 0  &&  did_version++ == 0)
 		printk(version);
 
-#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
 	dev = init_etherdev(dev, sizeof(struct speedo_private));
-#else
-	dev = init_etherdev(dev, sizeof(struct speedo_private), 0);
-#endif
+
+	if (dev->mem_start > 0) 
+		option = dev->mem_start;
+	else if (card_idx >= 0  &&  options[card_idx] >= 0)
+		option = options[card_idx];
+	else
+		option = 0;
 
 	/* Read the station address EEPROM before doing the reset.
 	   Perhaps this should even be done before accepting the device,
@@ -614,7 +566,7 @@
 	else
 		product = "Intel EtherExpress Pro 10/100";
 
-	printk(KERN_INFO "%s: %s at %#3x, ", dev->name, product, ioaddr);
+	printk(KERN_INFO "%s: %s at %#3lx, ", dev->name, product, ioaddr);
 
 	for (i = 0; i < 5; i++)
 		printk("%2.2X:", dev->dev_addr[i]);
@@ -643,17 +595,6 @@
 		if (eeprom[7] & 0x0700)
 			printk(KERN_INFO "    Secondary interface chip %s.\n",
 				   phys[(eeprom[7]>>8)&7]);
-#if defined(notdef)
-		/* ToDo: Read and set PHY registers through MDIO port. */
-		for (i = 0; i < 2; i++)
-			printk(KERN_INFO"  MDIO register %d is %4.4x.\n",
-				   i, mdio_read(ioaddr, eeprom[6] & 0x1f, i));
-		for (i = 5; i < 7; i++)
-			printk(KERN_INFO"  MDIO register %d is %4.4x.\n",
-				   i, mdio_read(ioaddr, eeprom[6] & 0x1f, i));
-		printk(KERN_INFO"  MDIO register %d is %4.4x.\n",
-			   25, mdio_read(ioaddr, eeprom[6] & 0x1f, 25));
-#endif
 		if (((eeprom[6]>>8) & 0x3f) == DP83840
 			||  ((eeprom[6]>>8) & 0x3f) == DP83840A) {
 			int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422;
@@ -663,13 +604,13 @@
 				   mdi_reg23);
 			mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23);
 		}
-		if ((options >= 0) && (options & 0x60)) {
+		if ((option >= 0) && (option & 0x70)) {
 			printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",
-				   (options & 0x20 ? 100 : 10),
-				   (options & 0x10 ? "full" : "half"));
+				   (option & 0x20 ? 100 : 10),
+				   (option & 0x10 ? "full" : "half"));
 			mdio_write(ioaddr, eeprom[6] & 0x1f, 0,
-					   ((options & 0x20) ? 0x2000 : 0) | 	/* 100mbps? */
-					   ((options & 0x10) ? 0x0100 : 0)); /* Full duplex? */
+					   ((option & 0x20) ? 0x2000 : 0) | 	/* 100mbps? */
+					   ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
 		}
 
 		/* Perform a system self-test. */
@@ -678,11 +619,7 @@
 		self_test_results[1] = -1;
 		outl(virt_to_bus(self_test_results) | 1, ioaddr + SCBPort);
 		do {
-#ifdef _LINUX_DELAY_H
 			udelay(10);
-#else
-			SLOW_DOWN_IO;
-#endif
 		} while (self_test_results[1] == -1  &&  --boguscnt >= 0);
 
 		if (boguscnt < 0) {		/* Test optimized out. */
@@ -719,12 +656,12 @@
 	sp->next_module = root_speedo_dev;
 	root_speedo_dev = dev;
 
+	sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
 	if (card_idx >= 0) {
 		if (full_duplex[card_idx] >= 0)
 			sp->full_duplex = full_duplex[card_idx];
-	} else
-		sp->full_duplex = options >= 0 && (options & 0x10) ? 1 : 0;
-	sp->default_port = options >= 0 ? (options & 0x0f) : 0;
+	}
+	sp->default_port = option >= 0 ? (option & 0x0f) : 0;
 
 	sp->phy[0] = eeprom[6];
 	sp->phy[1] = eeprom[7];
@@ -738,12 +675,8 @@
 	dev->hard_start_xmit = &speedo_start_xmit;
 	dev->stop = &speedo_close;
 	dev->get_stats = &speedo_get_stats;
-#ifdef NEW_MULTICAST
 	dev->set_multicast_list = &set_rx_mode;
-#endif
-#ifdef HAVE_PRIVATE_IOCTL
 	dev->do_ioctl = &speedo_ioctl;
-#endif
 
 	return;
 }
@@ -760,20 +693,15 @@
 #define EE_ENB			(0x4800 | EE_CS)
 
 /* Delay between EEPROM clock transitions.
-   This is a "nasty" timing loop, but PC compatible machines are defined
-   to delay an ISA compatible period for the SLOW_DOWN_IO macro.  */
-#ifdef _LINUX_DELAY_H
+   This will actually work with no delay on 33Mhz PCI.  */
 #define eeprom_delay(nanosec)		udelay(1);
-#else
-#define eeprom_delay(nanosec)	do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
-#endif
 
 /* The EEPROM commands include the alway-set leading bit. */
 #define EE_WRITE_CMD	(5 << 6)
 #define EE_READ_CMD		(6 << 6)
 #define EE_ERASE_CMD	(7 << 6)
 
-static int read_eeprom(int ioaddr, int location)
+static int read_eeprom(long ioaddr, int location)
 {
 	int i;
 	unsigned short retval = 0;
@@ -790,8 +718,6 @@
 		eeprom_delay(100);
 		outw(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
 		eeprom_delay(150);
-		outw(EE_ENB | dataval, ee_addr);	/* Finish EEPROM a clock tick. */
-		eeprom_delay(250);
 	}
 	outw(EE_ENB, ee_addr);
 
@@ -808,16 +734,11 @@
 	return retval;
 }
 
-static int mdio_read(int ioaddr, int phy_id, int location)
+static int mdio_read(long ioaddr, int phy_id, int location)
 {
-	int val, boguscnt = 64*4;		/* <64 usec. to complete, typ 27 ticks */
+	int val, boguscnt = 64*10;		/* <64 usec. to complete, typ 27 ticks */
 	outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI);
 	do {
-#ifdef _LINUX_DELAY_H
-		udelay(16);
-#else
-		SLOW_DOWN_IO;
-#endif
 		val = inl(ioaddr + SCBCtrlMDI);
 		if (--boguscnt < 0) {
 			printk(KERN_ERR " mdio_read() timed out with val = %8.8x.\n", val);
@@ -826,17 +747,12 @@
 	return val & 0xffff;
 }
 
-static int mdio_write(int ioaddr, int phy_id, int location, int value)
+static int mdio_write(long ioaddr, int phy_id, int location, int value)
 {
-	int val, boguscnt = 64*4;		/* <64 usec. to complete, typ 27 ticks */
+	int val, boguscnt = 64*10;		/* <64 usec. to complete, typ 27 ticks */
 	outl(0x04000000 | (location<<16) | (phy_id<<21) | value,
 		 ioaddr + SCBCtrlMDI);
 	do {
-#ifdef _LINUX_DELAY_H
-		udelay(16);
-#else
-		SLOW_DOWN_IO;
-#endif
 		val = inl(ioaddr + SCBCtrlMDI);
 		if (--boguscnt < 0) {
 			printk(KERN_ERR" mdio_write() timed out with val = %8.8x.\n", val);
@@ -850,25 +766,42 @@
 speedo_open(struct device *dev)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
-	int ioaddr = dev->base_addr;
+	long ioaddr = dev->base_addr;
 
 #ifdef notdef
 	/* We could reset the chip, but should not need to. */
 	outl(0, ioaddr + SCBPort);
-	for (i = 40; i >= 0; i--)
-		SLOW_DOWN_IO;			/* At least 250ns */
+	udelay(10);
 #endif
 
 	if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ,
 					"Intel EtherExpress Pro 10/100 Ethernet", dev)) {
 		return -EAGAIN;
 	}
-
 	if (speedo_debug > 1)
 		printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
 
 	MOD_INC_USE_COUNT;
 
+	/* Retrigger negotiation to reset previous errors. */
+	if ((sp->phy[0] & 0x8000) == 0) {
+		int phy_addr = sp->phy[0] & 0x1f;
+		/* Use 0x3300 for restarting NWay, other values to force xcvr:
+		   0x0000 10-HD
+		   0x0100 10-FD
+		   0x2000 100-HD 
+		   0x2100 100-FD
+		   0x
+		*/
+#ifdef notdef
+		int mii_ctrl[8] =
+		{ 0x3300, 0x3100, 0x0000, 0x0100, 0x2000, 0x2100, 0x0400, 0x3100};
+		mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->if_port & 7]);
+#else
+		mdio_write(ioaddr, phy_addr, 0, 0x3300);
+#endif
+	}
+
 	/* Load the statistics block address. */
 	wait_for_cmd_done(ioaddr + SCBCmd);
 	outl(virt_to_bus(&sp->lstats), ioaddr + SCBPointer);
@@ -908,6 +841,7 @@
 
 	dev->if_port = sp->default_port;
 
+	sp->in_interrupt = 0;
 	dev->tbusy = 0;
 	dev->interrupt = 0;
 	dev->start = 1;
@@ -952,7 +886,7 @@
 	int tickssofar = jiffies - sp->last_rx_time;
 
 	if (speedo_debug > 3) {
-		int ioaddr = dev->base_addr;
+		long ioaddr = dev->base_addr;
 		printk(KERN_DEBUG "%s: Media selection tick, status %4.4x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 	}
@@ -978,43 +912,32 @@
 	int i;
 
 	sp->cur_rx = 0;
-	sp->dirty_rx = RX_RING_SIZE - 1;
 
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		struct sk_buff *skb;
-#ifndef KERNEL_1_2
 		skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-#else
-		skb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC);
-#endif
 		sp->rx_skbuff[i] = skb;
 		if (skb == NULL)
-			break;			/* Bad news!  */
+			break;			/* OK.  Just initially short of Rx bufs. */
 		skb->dev = dev;			/* Mark as being used by this device. */
-
-#if LINUX_VERSION_CODE >= 0x10300
 		rxf = (struct RxFD *)skb->tail;
-		skb_reserve(skb, sizeof(struct RxFD));
-#else
-		/* Save the data in the header region -- it's restored later. */
-		rxf = (struct RxFD *)(skb->data - sizeof(struct RxFD));
-		memcpy(&sp->saved_skhead[i], rxf, sizeof(struct RxFD));
-#endif
 		sp->rx_ringp[i] = rxf;
+		skb_reserve(skb, sizeof(struct RxFD));
 		if (last_rxf)
 			last_rxf->link = virt_to_bus(rxf);
 		last_rxf = rxf;
 		rxf->status = 0x00000001; 			/* '1' is flag value only. */
 		rxf->link = 0;						/* None yet. */
-#if LINUX_VERSION_CODE < 0x10300
 		/* This field unused by i82557, we use it as a consistency check. */
-		rxf->rx_buf_addr = virt_to_bus(skb->data);
+#ifdef final_version
+		rxf->rx_buf_addr = 0xffffffff;
 #else
 		rxf->rx_buf_addr = virt_to_bus(skb->tail);
 #endif
 		rxf->count = 0;
 		rxf->size = PKT_BUF_SZ;
 	}
+	sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 	/* Mark the last entry as end-of-list. */
 	last_rxf->status = 0xC0000002; 			/* '2' is flag value only. */
 	sp->last_rxf = last_rxf;
@@ -1023,28 +946,12 @@
 static void speedo_tx_timeout(struct device *dev)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
-	int ioaddr = dev->base_addr;
-	int i;
+	long ioaddr = dev->base_addr;
 
 	printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
 		   "command %4.4x.\n",
 		   dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd));
-#ifndef final_version
-	printk(KERN_WARNING "%s:  Tx timeout  fill index %d  scavenge index %d.\n",
-		   dev->name, sp->cur_tx, sp->dirty_tx);
-	printk(KERN_WARNING "    Tx queue ");
-	for (i = 0; i < TX_RING_SIZE; i++)
-	  printk(" %8.8x", (int)sp->tx_ring[i].status);
-	printk(".\n" KERN_WARNING "    Rx ring ");
-	for (i = 0; i < RX_RING_SIZE; i++)
-	  printk(" %8.8x", (int)sp->rx_ringp[i]->status);
-	printk(".\n");
 
-#else
-	dev->if_port ^= 1;
-	printk(KERN_WARNING "  (Media type switching not yet implemented.)\n");
-	/* Do not do 'dev->tbusy = 0;' there -- it is incorrect. */
-#endif
 	if ((inw(ioaddr + SCBStatus) & 0x00C0) != 0x0080) {
 	  printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
 			 dev->name);
@@ -1054,9 +961,14 @@
 	} else {
 	  outw(DRVR_INT, ioaddr + SCBCmd);
 	}
-	/* Reset the MII transceiver. */
-	if ((sp->phy[0] & 0x8000) == 0)
-		mdio_write(ioaddr, sp->phy[0] & 0x1f, 0, 0x8000);
+	/* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
+	if ((sp->phy[0] & 0x8000) == 0) {
+		int phy_addr = sp->phy[0] & 0x1f;
+		mdio_write(ioaddr, phy_addr, 0, 0x0400);
+		mdio_write(ioaddr, phy_addr, 1, 0x0000);
+		mdio_write(ioaddr, phy_addr, 4, 0x0000);
+		mdio_write(ioaddr, phy_addr, 0, 0x8000);
+	}
 	sp->stats.tx_errors++;
 	dev->trans_start = jiffies;
 	return;
@@ -1066,7 +978,7 @@
 speedo_start_xmit(struct sk_buff *skb, struct device *dev)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
-	int ioaddr = dev->base_addr;
+	long ioaddr = dev->base_addr;
 	int entry;
 
 	/* Block a timer-based transmit from overlapping.  This could better be
@@ -1082,7 +994,7 @@
 			return 1;
 		}
 		speedo_tx_timeout(dev);
-		return 0;
+		return 1;
 	}
 
 	/* Caution: the write order is important here, set the base address
@@ -1103,12 +1015,12 @@
 		sp->tx_ring[entry].link =
 		  virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
 		sp->tx_ring[entry].tx_desc_addr =
-		  virt_to_bus(&sp->tx_ring[entry].tx_buf_addr);
+		  virt_to_bus(&sp->tx_ring[entry].tx_buf_addr0);
 		/* The data region is always in one buffer descriptor, Tx FIFO
 		   threshold of 256. */
 		sp->tx_ring[entry].count = 0x01208000;
-		sp->tx_ring[entry].tx_buf_addr = virt_to_bus(skb->data);
-		sp->tx_ring[entry].tx_buf_size = skb->len;
+		sp->tx_ring[entry].tx_buf_addr0 = virt_to_bus(skb->data);
+		sp->tx_ring[entry].tx_buf_size0 = skb->len;
 		/* Todo: perhaps leave the interrupt bit set if the Tx queue is more
 		   than half full.  Argument against: we should be receiving packets
 		   and scavenging the queue.  Argument for: if so, it shouldn't
@@ -1125,7 +1037,7 @@
 	if (sp->cur_tx - sp->dirty_tx > TX_RING_SIZE - 3)
 		sp->tx_full = 1;
 	else
-		dev->tbusy = 0;
+		clear_bit(0, (void*)&dev->tbusy);
 
 	dev->trans_start = jiffies;
 
@@ -1138,7 +1050,7 @@
 {
 	struct device *dev = (struct device *)dev_instance;
 	struct speedo_private *sp;
-	int ioaddr, boguscnt = max_interrupt_work;
+	long ioaddr, boguscnt = max_interrupt_work;
 	unsigned short status;
 
 #ifndef final_version
@@ -1151,8 +1063,11 @@
 	ioaddr = dev->base_addr;
 	sp = (struct speedo_private *)dev->priv;
 #ifndef final_version
-	if (dev->interrupt) {
-		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
+	/* A lock to prevent simultaneous entry on SMP machines. */
+	if (test_and_set_bit(0, (void*)&sp->in_interrupt)) {
+		printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
+			   dev->name);
+		sp->in_interrupt = 0;	/* Avoid halting machine. */
 		return;
 	}
 	dev->interrupt = 1;
@@ -1174,19 +1089,6 @@
 			speedo_rx(dev);
 
 		if (status & 0x1000) {
-#ifdef notdef
-		  int i;
-		  printk(KERN_WARNING"%s: The EEPro100 receiver left the ready"
-				 " state -- %4.4x!  Index %d (%d).\n", dev->name, status,
-				 sp->cur_rx, sp->cur_rx % RX_RING_SIZE);
-		  printk(KERN_WARNING "   Rx ring:\n ");
-		  for (i = 0; i < RX_RING_SIZE; i++)
-			printk("   %d %8.8x %8.8x %8.8x %d %d.\n",
-				   i, sp->rx_ringp[i]->status, sp->rx_ringp[i]->link,
-				   sp->rx_ringp[i]->rx_buf_addr, sp->rx_ringp[i]->count,
-				   sp->rx_ringp[i]->size);
-#endif
-
 		  if ((status & 0x003c) == 0x0028) /* No more Rx buffers. */
 			outw(RX_RESUMENR, ioaddr + SCBCmd);
 		  else if ((status & 0x003c) == 0x0008) { /* No resources (why?!) */
@@ -1214,7 +1116,7 @@
 				/* Free the original skb. */
 				if (sp->tx_skbuff[entry]) {
 					sp->stats.tx_packets++;	/* Count only user packets. */
-					dev_kfree_skb(sp->tx_skbuff[entry]);
+					dev_free_skb(sp->tx_skbuff[entry]);
 					sp->tx_skbuff[entry] = 0;
 				}
 				dirty_tx++;
@@ -1233,7 +1135,7 @@
 				&& dirty_tx > sp->cur_tx - TX_RING_SIZE + 2) {
 				/* The ring is no longer full, clear tbusy. */
 				sp->tx_full = 0;
-				dev->tbusy = 0;
+				clear_bit(0, (void*)&dev->tbusy);
 				mark_bh(NET_BH);
 			}
 
@@ -1253,19 +1155,8 @@
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 
-#ifndef final_version
-	/* Special code for testing *only*. */
-	{
-		static int stopit = 100;
-		if (dev->start == 0  &&  --stopit < 0) {
-			printk(KERN_ALERT "%s: Emergency stop, interrupt is stuck.\n",
-				   dev->name);
-			free_irq(irq, dev);
-		}
-	}
-#endif
-
 	dev->interrupt = 0;
+	clear_bit(0, (void*)&sp->in_interrupt);
 	return;
 }
 
@@ -1275,150 +1166,96 @@
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	int entry = sp->cur_rx % RX_RING_SIZE;
 	int status;
+	int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx;
 
 	if (speedo_debug > 4)
 		printk(KERN_DEBUG " In speedo_rx().\n");
 	/* If we own the next entry, it's a new packet. Send it up. */
-	while ((status = sp->rx_ringp[entry]->status) & RX_COMPLETE) {
+	while (sp->rx_ringp[entry] != NULL &&
+		   (status = sp->rx_ringp[entry]->status) & RxComplete) {
 
 		if (speedo_debug > 4)
 			printk(KERN_DEBUG "  speedo_rx() status %8.8x len %d.\n", status,
 				   sp->rx_ringp[entry]->count & 0x3fff);
-		if (status & 0x0200) {
-			printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "
-				   "status %8.8x!\n", dev->name, status);
-		} else if ( ! (status & 0x2000)) {
-			/* There was a fatal error.  This *should* be impossible. */
-			sp->stats.rx_errors++;
-			printk(KERN_ERR "%s: Anomalous event in speedo_rx(), status %8.8x.\n",
-				   dev->name, status);
+		if ((status & (RxErrTooBig|RxOK)) != RxOK) {
+			if (status & RxErrTooBig)
+				printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "
+					   "status %8.8x!\n", dev->name, status);
+			else if ( ! (status & 0x2000)) {
+				/* There was a fatal error.  This *should* be impossible. */
+				sp->stats.rx_errors++;
+				printk(KERN_ERR "%s: Anomalous event in speedo_rx(), "
+					   "status %8.8x.\n",
+					   dev->name, status);
+			}
 		} else {
-			/* Malloc up new buffer, compatible with net-2e. */
 			int pkt_len = sp->rx_ringp[entry]->count & 0x3fff;
 			struct sk_buff *skb;
-			int rx_in_place = 0;
 
 			/* Check if the packet is long enough to just accept without
 			   copying to a properly sized skbuff. */
-			if (pkt_len > rx_copybreak) {
-				struct sk_buff *newskb;
-				char *temp;
-
-				/* Pass up the skb already on the Rx ring. */
-				skb = sp->rx_skbuff[entry];
-#ifdef KERNEL_1_2
-				temp = skb->data;
-				if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
-					printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
-						   " in speedo_rx: %p vs. %p / %p.\n", dev->name,
-						   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
-						   temp, skb->data);
-				/* Get a fresh skbuff to replace the filled one. */
-				newskb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC);
-#else
-				temp = skb_put(skb, pkt_len);
-				if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
-					printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
-						   " in speedo_rx: %8.8x vs. %p / %p.\n", dev->name,
-						   sp->rx_ringp[entry]->rx_buf_addr, skb->head, temp);
-				/* Get a fresh skbuff to replace the filled one. */
-				newskb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-#endif
-				if (newskb) {
-					struct RxFD *rxf;
-					rx_in_place = 1;
-					sp->rx_skbuff[entry] = newskb;
-					newskb->dev = dev;
-#ifdef KERNEL_1_2
-					/* Restore the data in the old header region. */
-					memcpy(skb->data - sizeof(struct RxFD),
-						   &sp->saved_skhead[entry], sizeof(struct RxFD));
-					/* Save the data in this header region. */
-					rxf = (struct RxFD *)(newskb->data - sizeof(struct RxFD));
-					sp->rx_ringp[entry] = rxf;
-					memcpy(&sp->saved_skhead[entry], rxf, sizeof(struct RxFD));
-					rxf->rx_buf_addr = virt_to_bus(newskb->data);
-#else
-					rxf = sp->rx_ringp[entry] = (struct RxFD *)newskb->tail;
-					skb_reserve(newskb, sizeof(struct RxFD));
-					/* Unused by i82557, consistency check only. */
-					rxf->rx_buf_addr = virt_to_bus(newskb->tail);
-#endif
-					rxf->status = 0x00000001;
-				} else			/* No memory, drop the packet. */
-				  skb = 0;
-			} else
-#ifdef KERNEL_1_2
-				skb = alloc_skb(pkt_len, GFP_ATOMIC);
-#else
-				skb = dev_alloc_skb(pkt_len + 2);
-#endif
-			if (skb == NULL) {
-				int i;
-				printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name);
-				/* Check that at least two ring entries are free.
-				   If not, free one and mark stats->rx_dropped++. */
-				/* ToDo: This is not correct!!!!  We should count the number
-				   of linked-in Rx buffer to very that we have at least two
-				   remaining. */
-				for (i = 0; i < RX_RING_SIZE; i++)
-					if (! ((sp->rx_ringp[(entry+i) % RX_RING_SIZE]->status)
-						   & RX_COMPLETE))
-						break;
-
-				if (i > RX_RING_SIZE -2) {
-					sp->stats.rx_dropped++;
-					sp->rx_ringp[entry]->status = 0;
-					sp->cur_rx++;
-				}
-				break;
-			}
-			skb->dev = dev;
-#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
-			if (! rx_in_place) {
-				skb_reserve(skb, 2);	/* 16 byte align the data fields */
-#if defined(__i386__)   &&  notyet
+			if (pkt_len < rx_copybreak
+				&& (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
+				/* 'skb_put()' points to the start of sk_buff data area. */
+#if defined(__i386)   &&  notyet
 				/* Packet is in one chunk -- we can copy + cksum. */
-				eth_io_copy_and_sum(skb, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
+				eth_io_copy_and_sum(skb,
+								bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
 									pkt_len, 0);
 #else
 				memcpy(skb_put(skb, pkt_len),
 					   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len);
 #endif
+			} else {
+				void *temp;
+				/* Pass up the already-filled skbuff. */
+				skb = sp->rx_skbuff[entry];
+				sp->rx_skbuff[entry] = NULL;
+				temp = skb_put(skb, pkt_len);
+				if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
+					printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
+						   " in speedo_rx: %p vs. %p / %p.\n", dev->name,
+						   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
+						   skb->head, temp);
 			}
 			skb->protocol = eth_type_trans(skb, dev);
-#else
-#ifdef KERNEL_1_3
-#warning This code has only been tested with later 1.3.* kernels.
-			skb->len = pkt_len;
-			memcpy(skb->data, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
-				   pkt_len);
-			/* Needed for 1.3.*. */
-			skb->protocol = eth_type_trans(skb, dev);
-#else	/* KERNEL_1_2 */
-			skb->len = pkt_len;
-			if (! rx_in_place) {
-				memcpy(skb->data,
-					   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len);
-			}
-#endif
-#endif
 			netif_rx(skb);
 			sp->stats.rx_packets++;
 		}
+		entry = (++sp->cur_rx) % RX_RING_SIZE;
+		if (--rx_work_limit < 0)
+			break;
+	}
 
-		/*	ToDo: This is better than before, but should be checked. */
-		{
-			struct RxFD *rxf = sp->rx_ringp[entry];
-			rxf->status = 0xC0000003; 		/* '3' for verification only */
-			rxf->link = 0;			/* None yet. */
-			rxf->count = 0;
-			rxf->size = PKT_BUF_SZ;
-			sp->last_rxf->link = virt_to_bus(rxf);
-			sp->last_rxf->status &= ~0xC0000000;
-			sp->last_rxf = rxf;
-			entry = (++sp->cur_rx) % RX_RING_SIZE;
+	/* Refill the Rx ring buffers. */
+	for (; sp->dirty_rx < sp->cur_rx; sp->dirty_rx++) {
+		struct RxFD *rxf;
+		entry = sp->dirty_rx % RX_RING_SIZE;
+		if (sp->rx_skbuff[entry] == NULL) {
+			struct sk_buff *skb;
+			/* Get a fresh skbuff to replace the consumed one. */
+			skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
+			sp->rx_skbuff[entry] = skb;
+			if (skb == NULL) {
+				sp->rx_ringp[entry] = NULL;
+				break;			/* Better luck next time!  */
+			}
+			rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
+			skb->dev = dev;
+			skb_reserve(skb, sizeof(struct RxFD));
+			rxf->rx_buf_addr = virt_to_bus(skb->tail);
+		} else {
+			rxf = sp->rx_ringp[entry];
 		}
+		rxf->status = 0xC0000001; 	/* '2' for driver use only. */
+		rxf->link = 0;			/* None yet. */
+		rxf->count = 0;
+		rxf->size = PKT_BUF_SZ;
+		sp->last_rxf->link = virt_to_bus(rxf);
+		sp->last_rxf->status &= ~0xC0000000;
+		sp->last_rxf = rxf;
 	}
 
 	sp->last_rx_time = jiffies;
@@ -1428,7 +1265,7 @@
 static int
 speedo_close(struct device *dev)
 {
-	int ioaddr = dev->base_addr;
+	long ioaddr = dev->base_addr;
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	int i;
 
@@ -1454,7 +1291,7 @@
 		sp->rx_skbuff[i] = 0;
 		/* Clear the Rx descriptors. */
 		if (skb)
-			dev_kfree_skb(skb);
+			dev_free_skb(skb);
 	}
 
 	for (i = 0; i < TX_RING_SIZE; i++) {
@@ -1462,7 +1299,7 @@
 		sp->tx_skbuff[i] = 0;
 		/* Clear the Tx descriptors. */
 		if (skb)
-			dev_kfree_skb(skb);
+			dev_free_skb(skb);
 	}
 	if (sp->mc_setup_frm) {
 		kfree(sp->mc_setup_frm);
@@ -1507,7 +1344,7 @@
 speedo_get_stats(struct device *dev)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
-	int ioaddr = dev->base_addr;
+	long ioaddr = dev->base_addr;
 
 	if (sp->lstats.done_marker == 0xA007) {	/* Previous dump finished */
 		sp->stats.tx_aborted_errors += sp->lstats.tx_coll16_errs;
@@ -1530,11 +1367,10 @@
 	return &sp->stats;
 }
 
-#ifdef HAVE_PRIVATE_IOCTL
 static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
-	int ioaddr = dev->base_addr;
+	long ioaddr = dev->base_addr;
 	u16 *data = (u16 *)&rq->ifr_data;
 	int phy = sp->phy[0] & 0x1f;
 
@@ -1545,7 +1381,7 @@
 		data[3] = mdio_read(ioaddr, data[0], data[1]);
 		return 0;
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
-		if (!capable(CAP_NET_ADMIN))
+		if (!suser())
 			return -EPERM;
 		mdio_write(ioaddr, data[0], data[1], data[2]);
 		return 0;
@@ -1553,7 +1389,6 @@
 		return -EOPNOTSUPP;
 	}
 }
-#endif  /* HAVE_PRIVATE_IOCTL */
 
 /* Set or clear the multicast filter for this adaptor.
    This is very ugly with Intel chips -- we usually have to execute an
@@ -1568,14 +1403,15 @@
 set_rx_mode(struct device *dev)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
-	int ioaddr = dev->base_addr;
+	long ioaddr = dev->base_addr;
 	char new_rx_mode;
 	unsigned long flags;
 	int entry, i;
 
 	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
 		new_rx_mode = 3;
-	} else if (dev->flags & IFF_ALLMULTI) {
+	} else if ((dev->flags & IFF_ALLMULTI)  ||
+			   dev->mc_count > multicast_filter_limit) {
 		new_rx_mode = 1;
 	} else
 		new_rx_mode = 0;
@@ -1589,12 +1425,13 @@
 
 	if (new_rx_mode != sp->rx_mode) {
 		/* We must change the configuration. Construct a CmdConfig frame. */
-		memcpy(sp->config_cmd_data, basic_config_cmd,sizeof(basic_config_cmd));
+		memcpy(sp->config_cmd_data, i82558_config_cmd,
+			   sizeof(i82558_config_cmd));
 		sp->config_cmd_data[1] = (txfifo << 4) | rxfifo;
 		sp->config_cmd_data[4] = rxdmacount;
 		sp->config_cmd_data[5] = txdmacount + 0x80;
-		sp->config_cmd_data[15] = (new_rx_mode & 2) ? 0x49 : 0x48;
-		sp->config_cmd_data[19] = sp->full_duplex ? 0xC0 : 0x80;
+		sp->config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0;
+		sp->config_cmd_data[19] |= sp->full_duplex ? 0x40 : 0;
 		sp->config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
 		if (sp->phy[0] & 0x8000) {			/* Use the AUI port instead. */
 		  sp->config_cmd_data[15] |= 0x80;
@@ -1626,11 +1463,11 @@
 		}
 	}
 
-	if (new_rx_mode == 0  &&  dev->mc_count < 3) {
-		/* The simple case of 0-2 multicast list entries occurs often, and
+	if (new_rx_mode == 0  &&  dev->mc_count < 4) {
+		/* The simple case of 0-3 multicast list entries occurs often, and
 		   fits within one tx_ring[] entry. */
-		u16 *setup_params, *eaddrs;
 		struct dev_mc_list *mclist;
+		u16 *setup_params, *eaddrs;
 
 		save_flags(flags);
 		cli();
@@ -1658,11 +1495,9 @@
 		sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
 		restore_flags(flags);
 	} else if (new_rx_mode == 0) {
-		/* This does not work correctly, but why not? */
 		struct dev_mc_list *mclist;
-		u16 *eaddrs;
+		u16 *setup_params, *eaddrs;
 		struct descriptor *mc_setup_frm = sp->mc_setup_frm;
-		u16 *setup_params = (u16 *)mc_setup_frm->params;
 		int i;
 
 		if (sp->mc_setup_frm_len < 10 + dev->mc_count*6
@@ -1674,7 +1509,8 @@
 			sp->mc_setup_frm_len = 10 + dev->mc_count*6 + 24;
 			sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len, GFP_ATOMIC);
 			if (sp->mc_setup_frm == NULL) {
-			  printk(KERN_ERR "%s: Failed to allocate a setup frame.\n", dev->name);
+			  printk(KERN_ERR "%s: Failed to allocate a setup frame.\n",
+					 dev->name);
 				sp->rx_mode = -1; /* We failed, try again. */
 				return;
 			}
@@ -1688,7 +1524,7 @@
 		mc_setup_frm->status = 0;
 		mc_setup_frm->command = CmdSuspend | CmdIntr | CmdMulticastList;
 		/* Link set below. */
-		setup_params = (u16 *)mc_setup_frm->params;
+		setup_params = (u16 *)&mc_setup_frm->params;
 		*setup_params++ = dev->mc_count*6;
 		/* Fill in the multicast addresses. */
 		for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
@@ -1732,24 +1568,6 @@
 }
 
 #ifdef MODULE
-#if (LINUX_VERSION_CODE < VERSION(1,3,38))	/* 1.3.38 and later */
-char kernel_version[] = UTS_RELEASE;
-#endif
-
-#if LINUX_VERSION_CODE > 0x20118
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("Intel i82557/i82558 EtherExpressPro driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(congenb, "i");
-MODULE_PARM(txfifo, "i");
-MODULE_PARM(rxfifo, "i");
-MODULE_PARM(txdmacount, "i");
-MODULE_PARM(rxdmacount, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(max_interrupt_work, "i");
-#endif
 
 int
 init_module(void)
@@ -1796,7 +1614,8 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c"
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --recursive --new-file v2.1.111/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v2.1.111/linux/drivers/net/ibmtr.c	Thu Jul 16 18:09:25 1998
+++ linux/drivers/net/ibmtr.c	Sun Jul 26 23:35:56 1998
@@ -59,9 +59,10 @@
  *	Changes by Christopher Turcksin <wabbit@rtfc.demon.co.uk>
  *	+ Now compiles ok as a module again.
  *
- *	Changes by Paul Norton (pnorton@cts.com) :
+ *	Changes by Paul Norton (p.norton@computer.org) :
  *      + moved the header manipulation code in tr_tx and tr_rx to
  *        net/802/tr.c. (July 12 1997)
+ *      + add retry and timeout on open if cable disconnected. (May 5 1998)
  *      + lifted 2000 byte mtu limit. now depends on shared-RAM size.
  *        May 25 1998)
  */
@@ -929,9 +930,12 @@
 							      DPRINTK("No signal detected for Auto Speed Detection.\n");
 						      else if (open_error_code==0x11)
 						      {
-						      	      ti->open_status=FAILURE;
-						      	      DPRINTK("Ring broken/disconnected.\n");
-						      	      wake_up(&ti->wait_for_reset);
+							      if (ti->retry_count--) 
+								      DPRINTK("Ring broken/disconnected, retrying...\n");
+							      else {
+								      DPRINTK("Ring broken/disconnected, open failed.\n");
+								      ti->open_status = FAILURE;
+							      }
 						      }
 						      else DPRINTK("Unrecoverable error: error code = %04x.\n",
 								   open_error_code);
diff -u --recursive --new-file v2.1.111/linux/drivers/net/ibmtr.h linux/drivers/net/ibmtr.h
--- v2.1.111/linux/drivers/net/ibmtr.h	Thu Jul 16 18:09:25 1998
+++ linux/drivers/net/ibmtr.h	Sun Jul 26 23:35:56 1998
@@ -7,6 +7,7 @@
 #define TR_RESET_INTERVAL (HZ/20) /* 5 on PC = 50 ms */
 #define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */
 #define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */
+#define TR_RETRIES 6            /* number of open retries */ 
 
 #define TR_ISA 1
 #define TR_MCA 2
@@ -215,6 +216,7 @@
         struct timer_list tr_timer;
 	unsigned char ring_speed;
 	__u32 func_addr;
+	unsigned int retry_count;
 };
 
 /* token ring adapter commands */
diff -u --recursive --new-file v2.1.111/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v2.1.111/linux/drivers/net/lance.c	Tue Jun  9 11:57:29 1998
+++ linux/drivers/net/lance.c	Sun Jul 26 23:35:56 1998
@@ -326,8 +326,7 @@
 	    struct pci_dev *pdev = NULL;
 		if (lance_debug > 1)
 			printk("lance.c: PCI is present, checking for devices...\n");
-		while (pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev)) {
-			unsigned char pci_bus, pci_device_fn;
+		while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev))) {
 			unsigned int pci_ioaddr;
 			unsigned short pci_command;
 
diff -u --recursive --new-file v2.1.111/linux/drivers/net/mace.c linux/drivers/net/mace.c
--- v2.1.111/linux/drivers/net/mace.c	Thu Apr 23 20:21:33 1998
+++ linux/drivers/net/mace.c	Sun Jul 26 23:35:56 1998
@@ -573,6 +573,7 @@
 	if ((fs & XMTSV) == 0) {
 	    printk(KERN_ERR "mace: xmtfs not valid! (fs=%x xc=%d ds=%x)\n",
 		   fs, xcount, dstat);
+	    return;
 	}
 	cp = mp->tx_cmds + NCMDS_TX * i;
 	stat = ld_le16(&cp->xfer_status);
@@ -765,7 +766,14 @@
 		if (frame_status & RS_FCSERR)
 		    ++mp->stats.rx_crc_errors;
 	    } else {
-		nb -= 8;
+		/* Mace feature AUTO_STRIP_RCV is on by default, dropping the
+		 * FCS on frames with 802.3 headers. This means that Ethernet 
+		 * frames have 8 extra octets at the end, while 802.3 frames 
+		 * have only 4. We need to correctly account for this. */
+		if (*(unsigned short *)(data+12) < 1536) /* 802.3 header */
+		    nb -= 4;
+		else	/* Ethernet header; mace includes FCS */
+		    nb -= 8;
 		skb_put(skb, nb);
 		skb->dev = dev;
 		skb->protocol = eth_type_trans(skb, dev);
diff -u --recursive --new-file v2.1.111/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c
--- v2.1.111/linux/drivers/net/myri_sbus.c	Thu Feb 12 20:56:08 1998
+++ linux/drivers/net/myri_sbus.c	Sun Jul 26 23:35:56 1998
@@ -1044,27 +1044,11 @@
 	dev->hard_start_xmit = &myri_start_xmit;
 	dev->get_stats = &myri_get_stats;
 	dev->set_multicast_list = &myri_set_multicast;
-	dev->irq = sdev->irqs[0].pri;
+	dev->irq = sdev->irqs[0];
 	dev->dma = 0;
 
 	/* Register interrupt handler now. */
 	DET(("Requesting MYRIcom IRQ line.\n"));
-#ifdef __sparc_v9__
-	if(sparc_cpu_model == sun4u) {
-		struct devid_cookie dcookie;
-
-		dcookie.real_dev_id = dev;
-		dcookie.imap = dcookie.iclr = 0;
-		dcookie.pil = -1;
-		dcookie.bus_cookie = sdev->my_bus;
-		if(request_irq(dev->irq, &myri_interrupt,
-			       (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
-			       "MyriCOM Ethernet", &dcookie)) {
-			printk("MyriCOM: Cannot register interrupt handler.\n");
-			return ENODEV;
-		}
-	} else
-#endif
 	if(request_irq(dev->irq, &myri_interrupt,
 		       SA_SHIRQ, "MyriCOM Ethernet", (void *) dev)) {
 		printk("MyriCOM: Cannot register interrupt handler.\n");
diff -u --recursive --new-file v2.1.111/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v2.1.111/linux/drivers/net/plip.c	Mon Feb 23 18:12:05 1998
+++ linux/drivers/net/plip.c	Sun Jul 26 23:35:56 1998
@@ -574,6 +574,7 @@
 		/* Inform the upper layer for the arrival of a packet. */
 		rcv->skb->protocol=eth_type_trans(rcv->skb, dev);
 		netif_rx(rcv->skb);
+		nl->enet_stats.rx_bytes += rcv->length.h;
 		nl->enet_stats.rx_packets++;
 		rcv->skb = NULL;
 		if (net_debug > 2)
@@ -741,6 +742,7 @@
 			      &snd->nibble, snd->checksum))
 			return TIMEOUT;
 
+		nl->enet_stats.tx_bytes += snd->skb->len;
 		dev_kfree_skb(snd->skb);
 		nl->enet_stats.tx_packets++;
 		snd->state = PLIP_PK_DONE;
diff -u --recursive --new-file v2.1.111/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c
--- v2.1.111/linux/drivers/net/seeq8005.c	Tue Mar 17 22:18:14 1998
+++ linux/drivers/net/seeq8005.c	Sun Jul 26 23:35:56 1998
@@ -372,6 +372,7 @@
 seeq8005_send_packet(struct sk_buff *skb, struct device *dev)
 {
 	int ioaddr = dev->base_addr;
+	struct net_local *lp = (struct net_local *)dev->priv;
 
 	if (dev->tbusy) {
 		/* If we get here, some higher level has decided we are broken.
@@ -397,6 +398,7 @@
 
 		hardware_send_packet(dev, buf, length); 
 		dev->trans_start = jiffies;
+		lp->stats.tx_bytes += length;
 	}
 	dev_kfree_skb (skb);
 
@@ -547,6 +549,7 @@
 			skb->protocol=eth_type_trans(skb,dev);
 			netif_rx(skb);
 			lp->stats.rx_packets++;
+			lp->stats.rx_bytes += pkt_len;
 		}
 	} while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN));
 
diff -u --recursive --new-file v2.1.111/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c
--- v2.1.111/linux/drivers/net/sk_g16.c	Tue Jul 21 00:15:31 1998
+++ linux/drivers/net/sk_g16.c	Sun Jul 26 23:35:56 1998
@@ -1250,6 +1250,8 @@
 	    */
 	   dev->tbusy = 0;
 	}
+
+	p->stats.tx_bytes += skb->len;
     }
     dev_kfree_skb(skb);
     return 0;  
@@ -1585,6 +1587,7 @@
 
 	    writeb(RX_OWN, rmdp->u.s.status);
 	    p->stats.rx_packets++;
+	    p->stats.rx_bytes += len;
 
 
 	    p->rmdnum++;
diff -u --recursive --new-file v2.1.111/linux/drivers/net/sonic.c linux/drivers/net/sonic.c
--- v2.1.111/linux/drivers/net/sonic.c	Thu Feb 12 20:56:09 1998
+++ linux/drivers/net/sonic.c	Sun Jul 26 23:35:56 1998
@@ -430,6 +430,7 @@
 	lp->tda[(lp->cur_tx-1) % SONIC_TDS_MASK].link &= ~SONIC_END_OF_LINKS;
     
     lp->cur_tx++;
+    lp->stats.tx_bytes += length;
     
     if (sonic_debug > 2)
       printk("sonic_send_packet: issueing Tx command\n");
@@ -610,6 +611,7 @@
 	    skb->protocol=eth_type_trans(skb,dev);
 	    netif_rx(skb);			/* pass the packet to upper layers */
 	    lp->stats.rx_packets++;
+	    lp->stats.rx_bytes += pkt_len;
 	    
 	} else {
 	    /* This should only happen, if we enable accepting broken packets. */
diff -u --recursive --new-file v2.1.111/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.1.111/linux/drivers/net/sunhme.c	Fri May  8 23:14:48 1998
+++ linux/drivers/net/sunhme.c	Sun Jul 26 23:35:56 1998
@@ -2098,6 +2098,7 @@
 }
 #endif
 
+#ifndef __sparc_v9__
 static void sun4c_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct device *dev            = (struct device *) dev_id;
@@ -2141,6 +2142,7 @@
 	dev->interrupt = 0;
 	HMD(("done\n"));
 }
+#endif
 
 static int happy_meal_open(struct device *dev)
 {
@@ -2148,6 +2150,7 @@
 	int res;
 
 	HMD(("happy_meal_open: "));
+#ifndef __sparc_v9__
 	if(sparc_cpu_model == sun4c) {
 		if(request_irq(dev->irq, &sun4c_happy_meal_interrupt,
 			       SA_SHIRQ, "HAPPY MEAL", (void *) dev)) {
@@ -2155,47 +2158,26 @@
 			printk("happy meal: Can't order irq %d to go.\n", dev->irq);
 			return -EAGAIN;
 		}
-	}
-#ifdef __sparc_v9__
-	else if(sparc_cpu_model == sun4u) {
-		struct devid_cookie dcookie;
-
+	} else
+#else
 #ifdef CONFIG_PCI
-		if(hp->happy_flags & HFLAG_PCI) {
-			if(request_irq(dev->irq, &pci_happy_meal_interrupt,
-				       SA_SHIRQ, "HAPPY MEAL (PCI)", dev)) {
-				HMD(("EAGAIN\n"));
-				printk("happy_meal(PCI: Can't order irq %d to go.\n",
-				       dev->irq);
-				return -EAGAIN;
-			}
-			goto v9_done;
-		}
-#endif
-		dcookie.real_dev_id = dev;
-		dcookie.imap = dcookie.iclr = 0;
-		dcookie.pil = -1;
-		dcookie.bus_cookie = hp->happy_sbus_dev->my_bus;
-		if(request_irq(dev->irq, &happy_meal_interrupt,
-			       (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
-			       "HAPPY MEAL", &dcookie)) {
-			HMD(("EAGAIN\n"));
-			printk("happy_meal(SBUS): Can't order irq %d to go.\n",
-			       dev->irq);
+	if(hp->happy_flags & HFLAG_PCI) {
+		if(request_irq(dev->irq, &pci_happy_meal_interrupt,
+			       SA_SHIRQ, "HAPPY MEAL (PCI)", dev)) {
+		HMD(("EAGAIN\n"));
+		printk("happy_meal(PCI: Can't order irq %s to go.\n",
+		       __irq_itoa(dev->irq));
 			return -EAGAIN;
 		}
-#ifdef CONFIG_PCI
-	v9_done:
+	} else
 #endif
-	}
 #endif
-	else {
-		if(request_irq(dev->irq, &happy_meal_interrupt,
-			       SA_SHIRQ, "HAPPY MEAL", (void *) dev)) {
-			HMD(("EAGAIN\n"));
-			printk("happy meal: Can't order irq %d to go.\n", dev->irq);
-			return -EAGAIN;
-		}
+	if(request_irq(dev->irq, &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;
 	}
 	HMD(("Init happy timer\n"));
 	init_timer(&hp->happy_timer);
@@ -2594,7 +2576,7 @@
 	dev->get_stats = &happy_meal_get_stats;
 	dev->set_multicast_list = &happy_meal_set_multicast;
 
-	dev->irq = sdev->irqs[0].pri;
+	dev->irq = sdev->irqs[0];
 	dev->dma = 0;
 	ether_setup(dev);
 #ifdef MODULE
diff -u --recursive --new-file v2.1.111/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- v2.1.111/linux/drivers/net/sunlance.c	Fri May  8 23:14:48 1998
+++ linux/drivers/net/sunlance.c	Sun Jul 26 23:35:56 1998
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.75 1998/04/24 12:29:50 davem Exp $
+/* $Id: sunlance.c,v 1.79 1998/06/04 09:54:58 jj Exp $
  * lance.c: Linux/Sparc/Lance driver
  *
  *	Written 1995, 1996 by Miguel de Icaza
@@ -672,39 +672,11 @@
 
 	last_dev = dev;
 
-#ifdef __sparc_v9__
-	if (sparc_cpu_model == sun4u) {
-		struct devid_cookie dcookie;
-
-		dcookie.real_dev_id = dev;
-		dcookie.imap = dcookie.iclr = 0;
-		dcookie.pil = -1;
-		dcookie.bus_cookie = lp->sbus;
-		if(request_irq(dev->irq, &lance_interrupt,
-			       (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
-			       lancestr, &dcookie)) {
-			printk ("Lance: Can't get irq %d\n", dev->irq);
-			return -EAGAIN;
-		}
-	}
-#else
-	if (sparc_cpu_model == sun4d) {
-		struct devid_cookie dcookie;
-
-		dcookie.real_dev_id = dev;
-		dcookie.bus_cookie = (void *)dev->base_addr;
-		if(request_irq(dev->irq, &lance_interrupt,
-			       (SA_SHIRQ | SA_DCOOKIE),
-			       lancestr, &dcookie)) {
-			printk ("Lance: Can't get irq %d\n", dev->irq);
-			return -EAGAIN;
-		}
-	} else if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ,
+	if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ,
 			 lancestr, (void *) dev)) {
-		printk ("Lance: Can't get irq %d\n", dev->irq);
+		printk ("Lance: Can't get irq %s\n", __irq_itoa(dev->irq));
 		return -EAGAIN;
 	}
-#endif	
 
 	/* Stop the Lance */
 	ll->rap = LE_CSR0;
@@ -1124,7 +1096,7 @@
 	dev->get_stats = &lance_get_stats;
 	dev->set_multicast_list = &lance_set_multicast;
 
-	dev->irq = (unsigned char) sdev->irqs [0].pri;
+	dev->irq = sdev->irqs[0];
 
 	dev->dma = 0;
 	ether_setup (dev);
@@ -1166,7 +1138,7 @@
 	if (idprom->id_machtype == (SM_SUN4|SM_4_330)) {
 		memset (&sdev, 0, sizeof(sdev));
 		sdev.reg_addrs[0].phys_addr = SUN4_300_ETH_PHYSADDR;
-		sdev.irqs[0].pri = 6;
+		sdev.irqs[0] = 6;
 		return sparc_lance_init(dev, &sdev, 0, 0);
 	}
 	return ENODEV;
diff -u --recursive --new-file v2.1.111/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c
--- v2.1.111/linux/drivers/net/sunqe.c	Sun Jun  7 11:16:32 1998
+++ linux/drivers/net/sunqe.c	Sun Jul 26 23:35:56 1998
@@ -1103,7 +1103,7 @@
 			qe_devs[i]->hard_start_xmit = qe_start_xmit;
 		qe_devs[i]->get_stats = qe_get_stats;
 		qe_devs[i]->set_multicast_list = qe_set_multicast;
-		qe_devs[i]->irq = (unsigned char) sdev->irqs[0].pri;
+		qe_devs[i]->irq = sdev->irqs[0];
 		qe_devs[i]->dma = 0;
 		ether_setup(qe_devs[i]);
 	}
@@ -1114,32 +1114,14 @@
 	 * for it now.
 	 */
 	if(sparc_cpu_model == sun4c) {
-		if(request_irq(sdev->irqs[0].pri, &sun4c_qec_interrupt,
+		if(request_irq(sdev->irqs[0], &sun4c_qec_interrupt,
 			       SA_SHIRQ, "QuadEther", (void *) qecp)) {
 			printk("QuadEther: Can't register QEC master irq handler.\n");
 			res = EAGAIN;
 			goto qec_free_devs;
 		}
-	}
-#ifdef __sparc_v9__
-	else if(sparc_cpu_model == sun4u) {
-		struct devid_cookie dcookie;
-
-		dcookie.real_dev_id = qecp;
-		dcookie.imap = dcookie.iclr = 0;
-		dcookie.pil = -1;
-		dcookie.bus_cookie = sdev->my_bus;
-		if(request_irq(sdev->irqs[0].pri, &qec_interrupt,
-			       (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
-			       "QuadEther", &dcookie)) {
-			printk("QuadEther: Can't register QEC master irq handler.\n");
-			res = EAGAIN;
-			goto qec_free_devs;
-		}
-	}
-#endif
-	else {
-		if(request_irq(sdev->irqs[0].pri, &qec_interrupt,
+	} else {
+		if(request_irq(sdev->irqs[0], &qec_interrupt,
 			       SA_SHIRQ, "QuadEther", (void *) qecp)) {
 			printk("QuadEther: Can't register QEC master irq handler.\n");
 			res = EAGAIN;
@@ -1241,7 +1223,7 @@
 			unregister_netdev(root_qec_dev->qes[i]->dev);
 			kfree(root_qec_dev->qes[i]);
 		}
-		free_irq(root_qec_dev->qec_sbus_dev->irqs[0].pri, (void *)root_qec_dev);
+		free_irq(root_qec_dev->qec_sbus_dev->irqs[0], (void *)root_qec_dev);
 		kfree(root_qec_dev);
 		root_qec_dev = next_qec;
 	}
diff -u --recursive --new-file v2.1.111/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.1.111/linux/drivers/net/wavelan.c	Tue Jun 23 10:01:23 1998
+++ linux/drivers/net/wavelan.c	Sun Jul 26 23:35:56 1998
@@ -264,7 +264,7 @@
 static void
 psa_write(u_long	ioaddr,
 	  u_short	hacr,
-	  int		o,	/* Offset in psa */
+	  int		o,	/* Offset in PSA */
 	  u_char *	b,	/* Buffer in memory */
 	  int		n)	/* Length of buffer */
 {
@@ -403,7 +403,7 @@
  * Get the type of encryption available.
  */
 static inline int
-mmc_encr(u_long		ioaddr)	/* i/o port of the card */
+mmc_encr(u_long		ioaddr)	/* I/O port of the card */
 {
   int	temp;
 
@@ -420,7 +420,7 @@
  * I hope this one will be optimally inlined.
  */
 static inline void
-fee_wait(u_long		ioaddr,	/* i/o port of the card */
+fee_wait(u_long		ioaddr,	/* I/O port of the card */
 	 int		delay,	/* Base delay to wait for */
 	 int		number)	/* Number of time to wait */
 {
@@ -436,7 +436,7 @@
  * Read bytes from the Frequency EEPROM (frequency select cards).
  */
 static void
-fee_read(u_long		ioaddr,	/* i/o port of the card */
+fee_read(u_long		ioaddr,	/* I/O port of the card */
 	 u_short	o,	/* destination offset */
 	 u_short *	b,	/* data buffer */
 	 int		n)	/* number of registers */
@@ -471,7 +471,7 @@
  * Jean II
  */
 static void
-fee_write(u_long	ioaddr,	/* i/o port of the card */
+fee_write(u_long	ioaddr,	/* I/O port of the card */
 	  u_short	o,	/* destination offset */
 	  u_short *	b,	/* data buffer */
 	  int		n)	/* number of registers */
@@ -486,7 +486,7 @@
   fee_wait(ioaddr, 10, 100);
 
   /* Read the protected register. */
-  printk("Protected 2 : %02X-%02X\n",
+  printk("Protected 2:  %02X-%02X\n",
 	 mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)),
 	 mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
 #endif	/* DOESNT_SEEM_TO_WORK */
@@ -501,7 +501,7 @@
   mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n);
   mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
 #ifdef DOESNT_SEEM_TO_WORK	/* disabled */
-  /* Or use : */
+  /* or use: */
   mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR);
 #endif	/* DOESNT_SEEM_TO_WORK */
 
@@ -758,7 +758,7 @@
       /* Read the first transmit buffer */
       obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), (unsigned char *)&tx_status, sizeof(tx_status));
 
-      /* Hack for reconfiguration... */
+      /* Hack for reconfiguration */
       if(tx_status == 0xFFFF)
 	if(!wv_config_complete(dev, ioaddr, lp))
 	  break;	/* Not completed */
@@ -787,7 +787,7 @@
 	    lp->tx_first_in_use -= NTXBLOCKS * TXBLOCKZ;
 	}
 
-      /* Hack for reconfiguration... */
+      /* Hack for reconfiguration */
       if(tx_status == 0xFFFF)
 	continue;
 
@@ -921,7 +921,7 @@
 static void
 wv_psa_show(psa_t *	p)
 {
-  printk(KERN_DEBUG "##### WaveLAN psa contents: #####\n");
+  printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n");
   printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
 	 p->psa_io_base_addr_1,
 	 p->psa_io_base_addr_2,
@@ -1107,10 +1107,10 @@
   printk(KERN_DEBUG "status: ");
   printk("stat 0x%x[%s%s%s%s] ",
 	 (scb.scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA | SCB_ST_RNR)) >> 12,
-	 (scb.scb_status & SCB_ST_CX) ? "cmd completion interrupt," : "",
+	 (scb.scb_status & SCB_ST_CX) ? "command completion interrupt," : "",
 	 (scb.scb_status & SCB_ST_FR) ? "frame received," : "",
-	 (scb.scb_status & SCB_ST_CNA) ? "cmd unit not active," : "",
-	 (scb.scb_status & SCB_ST_RNR) ? "rcv unit not ready," : "");
+	 (scb.scb_status & SCB_ST_CNA) ? "command unit not active," : "",
+	 (scb.scb_status & SCB_ST_RNR) ? "receiving unit not ready," : "");
   printk("cus 0x%x[%s%s%s] ",
 	 (scb.scb_status & SCB_ST_CUS) >> 8,
 	 ((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_IDLE) ? "idle" : "",
@@ -1166,7 +1166,7 @@
   printk(KERN_DEBUG "##### WaveLAN i82586 receiver unit status: #####\n");
   printk(KERN_DEBUG "ru:");
   /*
-   * Not implemented yet...
+   * Not implemented yet
    */
   printk("\n");
 } /* wv_ru_show */
@@ -1335,7 +1335,7 @@
 #endif
 
 #ifdef DEBUG_BASIC_SHOW
-  /* Now, let's go for the basic stuff */
+  /* Now, let's go for the basic stuff. */
   printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr);
   for(i = 0; i < WAVELAN_ADDR_SIZE; i++)
     printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
@@ -1353,9 +1353,8 @@
     {
       unsigned short	freq;
 
-      /* Ask the EEPROM to read the frequency from the first area */
-      fee_read(ioaddr, 0x00 /* 1st area - frequency... */,
-	       &freq, 1);
+      /* Ask the EEPROM to read the frequency from the first area. */
+      fee_read(ioaddr, 0x00, &freq, 1);
 
       /* Print frequency */
       printk(", 2.00, %ld", (freq >> 6) + 2400L);
@@ -1539,16 +1538,16 @@
   return 0;
 }
 
-#ifdef WIRELESS_EXT	/* if wireless extension exists in the kernel */
+#ifdef WIRELESS_EXT	/* if wireless extensions exist in the kernel */
 
 /*------------------------------------------------------------------*/
 /*
- * Frequency setting (for hardware able of it)
- * It's a bit complicated and you don't really want to look into it...
+ * Frequency setting (for hardware capable of it)
+ * It's a bit complicated and you don't really want to look into it.
  * (called in wavelan_ioctl)
  */
 static inline int
-wv_set_frequency(u_long		ioaddr,	/* i/o port of the card */
+wv_set_frequency(u_long		ioaddr,	/* I/O port of the card */
 		 iw_freq *	frequency)
 {
   const int	BAND_NUM = 10;	/* Number of bands */
@@ -1560,8 +1559,8 @@
   /* Setting by frequency */
   /* Theoretically, you may set any frequency between
    * the two limits with a 0.5 MHz precision. In practice,
-   * I don't want you to have trouble with local
-   * regulations. */
+   * I don't want you to have trouble with local regulations.
+   */
   if((frequency->e == 1) &&
      (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8))
     {
@@ -1587,8 +1586,7 @@
       u_short	table[10];	/* Authorized frequency table */
 
       /* Read the frequency table. */
-      fee_read(ioaddr, 0x71 /* frequency table */,
-	       table, 10);
+      fee_read(ioaddr, 0x71, table, 10);
 
 #ifdef DEBUG_IOCTL_INFO
       printk(KERN_DEBUG "Frequency table: ");
@@ -1616,29 +1614,26 @@
       unsigned short	area_verify[16];
       unsigned short	dac_verify[2];
       /* Corresponding gain (in the power adjust value table)
-       * see AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8
-       * & WCIN062D.DOC, page 6.2.9 */
+       * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8
+       * and WCIN062D.DOC, page 6.2.9. */
       unsigned short	power_limit[] = { 40, 80, 120, 160, 0 };
       int		power_band = 0;		/* Selected band */
       unsigned short	power_adjust;		/* Correct value */
 
-      /* Search for the gain */
+      /* Search for the gain. */
       power_band = 0;
       while((freq > power_limit[power_band]) &&
 	    (power_limit[++power_band] != 0))
 	;
 
       /* Read the first area. */
-      fee_read(ioaddr, 0x00,
-	       area, 16);
+      fee_read(ioaddr, 0x00, area, 16);
 
       /* Read the DAC. */
-      fee_read(ioaddr, 0x60,
-	       dac, 2);
+      fee_read(ioaddr, 0x60, dac, 2);
 
       /* Read the new power adjust value. */
-      fee_read(ioaddr, 0x6B - (power_band >> 1),
-	       &power_adjust, 1);
+      fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust, 1);
       if(power_band & 0x1)
 	power_adjust >>= 8;
       else
@@ -1682,15 +1677,13 @@
       fee_write(ioaddr, 0x60,
 		dac, 2);
 
-      /* We now should verify here that the writing of the EEPROM was OK. */
+      /* We now should verify here that the writing of the EEPROM went OK. */
 
       /* Reread the first area. */
-      fee_read(ioaddr, 0x00,
-	       area_verify, 16);
+      fee_read(ioaddr, 0x00, area_verify, 16);
 
       /* Reread the DAC. */
-      fee_read(ioaddr, 0x60,
-	       dac_verify, 2);
+      fee_read(ioaddr, 0x60, dac_verify, 2);
 
       /* Compare. */
       if(memcmp(area, area_verify, 16 * 2) ||
@@ -1710,16 +1703,16 @@
       mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
 	      MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
 
-      /* Wait until the download is finished */
+      /* Wait until the download is finished. */
       fee_wait(ioaddr, 100, 100);
 
       /* We must now download the power adjust value (gain) to
-       * the synthesizers (from the EEPROM - area 7 - DAC) */
+       * the synthesizers (from the EEPROM - area 7 - DAC). */
       mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61);
       mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
 	      MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
 
-      /* Wait until the download is finished */
+      /* Wait for the download to finish. */
       fee_wait(ioaddr, 100, 100);
 
 #ifdef DEBUG_IOCTL_INFO
@@ -1745,22 +1738,21 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Give the list of available frequencies
+ * Give the list of available frequencies.
  */
 static inline int
-wv_frequency_list(u_long	ioaddr,	/* i/o port of the card */
-		  iw_freq *	list,	/* List of frequency to fill */
+wv_frequency_list(u_long	ioaddr,	/* I/O port of the card */
+		  iw_freq *	list,	/* List of frequencies to fill */
 		  int		max)	/* Maximum number of frequencies */
 {
   u_short	table[10];	/* Authorized frequency table */
   long		freq = 0L;	/* offset to 2.4 GHz in .5 MHz + 12 MHz */
   int		i;		/* index in the table */
 
-  /* Read the frequency table */
-  fee_read(ioaddr, 0x71 /* frequency table */,
-	   table, 10);
+  /* Read the frequency table. */
+  fee_read(ioaddr, 0x71 /* frequency table */, table, 10);
 
-  /* Check all frequencies */
+  /* Check all frequencies. */
   i = 0;
   for(freq = 0; freq < 150; freq++)
     /* Look in the table if the frequency is allowed */
@@ -1837,8 +1829,8 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Perform ioctl:  configuration and information
- * This is here that are treated the wireless extensions (iwconfig)
+ * Perform ioctl for configuration and information.
+ * It is here that the wireless extensions are treated (iwconfig).
  */
 static int
 wavelan_ioctl(struct device *	dev,	/* device on which the ioctl is applied */
@@ -1857,7 +1849,7 @@
   printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
 #endif
 
-  /* Disable interrupts & save flags */
+  /* Disable interrupts and save flags. */
   x = wv_splhi();
 
   /* Look what is the request */
@@ -1866,21 +1858,21 @@
       /* --------------- WIRELESS EXTENSIONS --------------- */
 
     case SIOCGIWNAME:
-      strcpy(wrq->u.name, "Wavelan");
+      strcpy(wrq->u.name, "WaveLAN");
       break;
 
     case SIOCSIWNWID:
       /* Set NWID in WaveLAN. */
       if(wrq->u.nwid.on)
 	{
-	  /* Set NWID in psa */
+	  /* Set NWID in psa. */
 	  psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8;
 	  psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;
 	  psa.psa_nwid_select = 0x01;
 	  psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
 		    (unsigned char *)psa.psa_nwid, 3);
 
-	  /* Set NWID in mmc */
+	  /* Set NWID in mmc. */
 	  m.w.mmw_netw_id_l = wrq->u.nwid.nwid & 0xFF;
 	  m.w.mmw_netw_id_h = (wrq->u.nwid.nwid & 0xFF00) >> 8;
 	  mmc_write(ioaddr, (char *)&m.w.mmw_netw_id_l - (char *)&m,
@@ -1925,9 +1917,8 @@
 	{
 	  unsigned short	freq;
 
-	  /* Ask the EEPROM to read the frequency from the first area */
-	  fee_read(ioaddr, 0x00 /* 1st area - frequency... */,
-		   &freq, 1);
+	  /* Ask the EEPROM to read the frequency from the first area. */
+	  fee_read(ioaddr, 0x00, &freq, 1);
 	  wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
 	  wrq->u.freq.e = 1;
 	}
@@ -2096,7 +2087,7 @@
 	    { SIOCGIPHISTO, 0,	    IW_PRIV_TYPE_INT | 16, "gethisto" },
 	  };
 
-	  /* Verify the user buffer */
+	  /* Verify the user buffer. */
 	  ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
 			    sizeof(priv));
 	  if(ret)
@@ -2149,7 +2140,7 @@
 	  memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
 
 #ifdef DEBUG_IOCTL_INFO
-	  printk(KERN_DEBUG "SetSpy - Set of new addresses is: \n");
+	  printk(KERN_DEBUG "SetSpy:  set of new addresses is: \n");
 	  for(i = 0; i < wrq->u.data.length; i++)
 	    printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X \n",
 		   lp->spy_address[i][0],
@@ -2226,7 +2217,7 @@
 
 #ifdef HISTOGRAM
     case SIOCSIPHISTO:
-      /* Verif if the user is root */
+      /* Verify that the user is root. */
       if(!suser())
 	return -EPERM;
 
@@ -2416,10 +2407,11 @@
       u_char	stats[3];	/* signal level, noise level, signal quality */
 
       /* Read signal level, silence level and signal quality bytes. */
-      /* Note: in the PCMCIA hardware, these are part of the frame. It seems
+      /* Note: in the PCMCIA hardware, these are part of the frame.  It seems
        * that for the ISA hardware, it's nowhere to be found in the frame,
        * so I'm obliged to do this (it has a side effect on /proc/net/wireless).
-       * Any ideas? */
+       * Any ideas?
+       */
       mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
       mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3);
       mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
@@ -2631,14 +2623,14 @@
  * The principle:
  * Each block contains a transmit command, a NOP command,
  * a transmit block descriptor and a buffer.
- * The CU reads the transmit block which points to the tbd,
- * reads the tbd and the content of the buffer.
- * When it has finished with it, it goes to the next command
+ * The CU read the transmit block which point to the tbd,
+ * read the tbd and the content of the buffer.
+ * When it has finish with it, it goes to the next command
  * which in our case is the NOP. The NOP points on itself,
- * so the CU stops here.
+ * so the CU stop here.
  * When we add the next block, we modify the previous nop
  * to make it point on the new tx command.
- * Simple, isn't it?
+ * Simple, isn't it ?
  *
  * (called in wavelan_packet_xmit())
  */
@@ -2772,8 +2764,8 @@
 /*------------------------------------------------------------------*/
 /*
  * This routine is called when we want to send a packet (NET3 callback)
- * In this routine, we check if the hardware is ready to accept
- * the packet. We also prevent reentrance. Then, we call the function
+ * In this routine, we check if the harware is ready to accept
+ * the packet.  We also prevent reentrance.  Then we call the function
  * to send the packet.
  */
 static int
@@ -2876,7 +2868,7 @@
       /* Disable encryption */
       psa.psa_encryption_select = 0;
 
-      /* Set to standard values
+      /* Set to standard values:
        * 0x04 for AT,
        * 0x01 for MCA,
        * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document)
@@ -2891,7 +2883,7 @@
       psa.psa_conf_status |= 1;
 
 #ifdef USE_PSA_CONFIG
-      /* Write the psa */
+      /* Write the psa. */
       psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
 		(unsigned char *)psa.psa_nwid, 4);
       psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
@@ -2948,7 +2940,7 @@
   mmc_write(ioaddr, 0, (u_char *)&m, sizeof(m));
 
   /* The following code starts the modem of the 2.00 frequency
-   * selectable cards at power on. It's not strictly needed for the
+   * selectable cards at power on.  It's not strictly needed for the
    * following boots.
    * The original patch was by Joe Finney for the PCMCIA driver, but
    * I've cleaned it up a bit and added documentation.
diff -u --recursive --new-file v2.1.111/linux/drivers/net/wavelan.h linux/drivers/net/wavelan.h
--- v2.1.111/linux/drivers/net/wavelan.h	Mon Mar 17 14:54:26 1997
+++ linux/drivers/net/wavelan.h	Sun Jul 26 23:35:56 1998
@@ -1,34 +1,34 @@
 /*
- *	Wavelan ISA driver
+ *	WaveLAN ISA driver
  *
  *		Jean II - HPLB '96
  *
  * Reorganisation and extension of the driver.
- * Original copyrigth follow. See wavelan.p.h for details.
+ * Original copyright follows. See wavelan.p.h for details.
  *
- * This file contain the declarations of the Wavelan hardware. Note that
- * the Wavelan ISA include a i82586 controler (see definitions in
+ * This file contains the declarations for the WaveLAN hardware. Note that
+ * the WaveLAN ISA includes a i82586 controller (see definitions in
  * file i82586.h).
  *
- * The main difference between the ISA hardware and the pcmcia one is
- * the Ethernet Controler (i82586 instead of i82593).
- * The i82586 allow multiple transmit buffers. The PSA need to be accessed
+ * The main difference between the ISA hardware and the PCMCIA one is
+ * the Ethernet controller (i82586 instead of i82593).
+ * The i82586 allows multiple transmit buffers.  The PSA needs to be accessed
  * through the host interface.
  */
 
 #ifndef _WAVELAN_H
 #define	_WAVELAN_H
 
-/* The detection of the wavelan card is made by reading the MAC
- * address from the card and checking it. If you have a non AT&T
- * product (OEM, like DEC RoamAbout, or Digital Ocean, Epson, ...),
- * you might need to modify this part to accomodate your hardware...
+/* Detection of the WaveLAN card is done by reading the MAC
+ * address from the card and checking it.  If you have a non-AT&T
+ * product (OEM, like DEC RoamAbout, Digital Ocean, or Epson),
+ * you might need to modify this part to accommodate your hardware.
  */
 const char	MAC_ADDRESSES[][3] =
 {
-  { 0x08, 0x00, 0x0E },		/* AT&T Wavelan (standard) & DEC RoamAbout */
-  { 0x08, 0x00, 0x6A },		/* AT&T Wavelan (alternate) */
-  /* Add your card here and send me the patch ! */
+  { 0x08, 0x00, 0x0E },		/* AT&T WaveLAN (standard) & DEC RoamAbout */
+  { 0x08, 0x00, 0x6A },		/* AT&T WaveLAN (alternate) */
+  /* Add your card here and send me the patch! */
 };
 
 #define WAVELAN_ADDR_SIZE	6	/* Size of a MAC address */
@@ -49,7 +49,7 @@
 	unsigned short	hu_command;		/* Command register */
 #define		HACR_RESET		0x0001	/* Reset board */
 #define		HACR_CA			0x0002	/* Set Channel Attention for 82586 */
-#define		HACR_16BITS		0x0004	/* 16 bits operation (0 => 8bits) */
+#define		HACR_16BITS		0x0004	/* 16-bit operation (0 => 8bits) */
 #define		HACR_OUT0		0x0008	/* General purpose output pin 0 */
 						/* not used - must be 1 */
 #define		HACR_OUT1		0x0010	/* General purpose output pin 1 */
@@ -112,11 +112,11 @@
 /************************** MEMORY LAYOUT **************************/
 
 /*
- * Onboard 64k RAM layout.
+ * Onboard 64 k RAM layout.
  * (Offsets from 0x0000.)
  */
-#define OFFSET_RU		0x0000		/* 75 % memory */
-#define OFFSET_CU		0xC000		/* 25 % memory */
+#define OFFSET_RU		0x0000		/* 75% memory */
+#define OFFSET_CU		0xC000		/* 25% memory */
 #define OFFSET_SCB		(OFFSET_ISCP - sizeof(scb_t))
 #define OFFSET_ISCP		(OFFSET_SCP - sizeof(iscp_t))
 #define OFFSET_SCP		I82586_SCP_ADDR
@@ -151,26 +151,26 @@
   unsigned char	psa_univ_local_sel;	/* [0x1C] Universal Local Selection */
 #define		PSA_UNIVERSAL	0		/* Universal (factory) */
 #define		PSA_LOCAL	1		/* Local */
-  unsigned char	psa_comp_number;	/* [0x1D] Compatability Number: */
-#define		PSA_COMP_PC_AT_915	0 	/* PC-AT 915 MHz	*/
-#define		PSA_COMP_PC_MC_915	1 	/* PC-MC 915 MHz	*/
-#define		PSA_COMP_PC_AT_2400	2 	/* PC-AT 2.4 GHz	*/
-#define		PSA_COMP_PC_MC_2400	3 	/* PC-MC 2.4 GHz	*/
+  unsigned char	psa_comp_number;	/* [0x1D] Compatibility Number:	 */
+#define		PSA_COMP_PC_AT_915	0 	/* PC-AT 915 MHz 	 */
+#define		PSA_COMP_PC_MC_915	1 	/* PC-MC 915 MHz	 */
+#define		PSA_COMP_PC_AT_2400	2 	/* PC-AT 2.4 GHz	 */
+#define		PSA_COMP_PC_MC_2400	3 	/* PC-MC 2.4 GHz 	 */
 #define		PSA_COMP_PCMCIA_915	4 	/* PCMCIA 915 MHz or 2.0 */
   unsigned char	psa_thr_pre_set;	/* [0x1E] Modem Threshold Preset */
   unsigned char	psa_feature_select;	/* [0x1F] Call code required (1=on) */
 #define		PSA_FEATURE_CALL_CODE	0x01 	/* Call code required (Japan) */
-  unsigned char	psa_subband;		/* [0x20] Subband	*/
+  unsigned char	psa_subband;		/* [0x20] Subband	  */
 #define		PSA_SUBBAND_915		0	/* 915 MHz or 2.0 */
-#define		PSA_SUBBAND_2425	1	/* 2425 MHz	*/
-#define		PSA_SUBBAND_2460	2	/* 2460 MHz	*/
-#define		PSA_SUBBAND_2484	3	/* 2484 MHz	*/
-#define		PSA_SUBBAND_2430_5	4	/* 2430.5 MHz	*/
+#define		PSA_SUBBAND_2425	1	/* 2425 MHz	  */
+#define		PSA_SUBBAND_2460	2	/* 2460 MHz	  */
+#define		PSA_SUBBAND_2484	3	/* 2484 MHz	  */
+#define		PSA_SUBBAND_2430_5	4	/* 2430.5 MHz	  */
   unsigned char	psa_quality_thr;	/* [0x21] Modem Quality Threshold */
-  unsigned char	psa_mod_delay;		/* [0x22] Modem Delay ??? (reserved) */
+  unsigned char	psa_mod_delay;		/* [0x22] Modem Delay (?) (reserved) */
   unsigned char	psa_nwid[2];		/* [0x23-0x24] Network ID */
-  unsigned char	psa_nwid_select;	/* [0x25] Network ID Select On Off */
-  unsigned char	psa_encryption_select;	/* [0x26] Encryption On Off */
+  unsigned char	psa_nwid_select;	/* [0x25] Network ID Select On/Off */
+  unsigned char	psa_encryption_select;	/* [0x26] Encryption On/Off */
   unsigned char	psa_encryption_key[8];	/* [0x27-0x2E] Encryption Key */
   unsigned char	psa_databus_width;	/* [0x2F] AT bus width select 8/16 */
   unsigned char	psa_call_code[8];	/* [0x30-0x37] (Japan) Call Code */
@@ -183,8 +183,8 @@
 
 #define	PSA_SIZE	64
 
-/* Calculate offset of a field in the above structure
- * Warning : only even addresses are used */
+/* Calculate offset of a field in the above structure.
+ * Warning:  only even addresses are used. */
 #define	psaoff(p,f) 	((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL))
 
 /******************** MODEM MANAGEMENT INTERFACE ********************/
@@ -196,25 +196,25 @@
 struct mmw_t
 {
   unsigned char	mmw_encr_key[8];	/* encryption key */
-  unsigned char	mmw_encr_enable;	/* enable/disable encryption */
-#define	MMW_ENCR_ENABLE_MODE	0x02	/* Mode of security option */
-#define	MMW_ENCR_ENABLE_EN	0x01	/* Enable security option */
+  unsigned char	mmw_encr_enable;	/* Enable or disable encryption. */
+#define	MMW_ENCR_ENABLE_MODE	0x02	/* mode of security option */
+#define	MMW_ENCR_ENABLE_EN	0x01	/* Enable security option. */
   unsigned char	mmw_unused0[1];		/* unused */
-  unsigned char	mmw_des_io_invert;	/* Encryption option */
-#define	MMW_DES_IO_INVERT_RES	0x0F	/* Reserved */
-#define	MMW_DES_IO_INVERT_CTRL	0xF0	/* Control ??? (set to 0) */
+  unsigned char	mmw_des_io_invert;	/* encryption option */
+#define	MMW_DES_IO_INVERT_RES	0x0F	/* reserved */
+#define	MMW_DES_IO_INVERT_CTRL	0xF0	/* control (?) (set to 0) */
   unsigned char	mmw_unused1[5];		/* unused */
   unsigned char	mmw_loopt_sel;		/* looptest selection */
-#define	MMW_LOOPT_SEL_DIS_NWID	0x40	/* disable NWID filtering */
-#define	MMW_LOOPT_SEL_INT	0x20	/* activate Attention Request */
-#define	MMW_LOOPT_SEL_LS	0x10	/* looptest w/o collision avoidance */
+#define	MMW_LOOPT_SEL_DIS_NWID	0x40	/* Disable NWID filtering. */
+#define	MMW_LOOPT_SEL_INT	0x20	/* Activate Attention Request. */
+#define	MMW_LOOPT_SEL_LS	0x10	/* looptest, no collision avoidance */
 #define MMW_LOOPT_SEL_LT3A	0x08	/* looptest 3a */
 #define	MMW_LOOPT_SEL_LT3B	0x04	/* looptest 3b */
 #define	MMW_LOOPT_SEL_LT3C	0x02	/* looptest 3c */
 #define	MMW_LOOPT_SEL_LT3D	0x01	/* looptest 3d */
   unsigned char	mmw_jabber_enable;	/* jabber timer enable */
   /* Abort transmissions > 200 ms */
-  unsigned char	mmw_freeze;		/* freeze / unfreeeze signal level */
+  unsigned char	mmw_freeze;		/* freeze or unfreeze signal level */
   /* 0 : signal level & qual updated for every new message, 1 : frozen */
   unsigned char	mmw_anten_sel;		/* antenna selection */
 #define MMW_ANTEN_SEL_SEL	0x01	/* direct antenna selection */
@@ -227,7 +227,7 @@
   unsigned char	mmw_thr_pre_set;	/* level threshold preset */
   /* Discard all packet with signal < this value (4) */
   unsigned char	mmw_decay_prm;		/* decay parameters */
-  unsigned char	mmw_decay_updat_prm;	/* decay update parameterz */
+  unsigned char	mmw_decay_updat_prm;	/* decay update parameters */
   unsigned char	mmw_quality_thr;	/* quality (z-quotient) threshold */
   /* Discard all packet with quality < this value (3) */
   unsigned char	mmw_netw_id_l;		/* NWID low order byte */
@@ -237,31 +237,31 @@
   /* 2.0 Hardware extension - frequency selection support */
   unsigned char	mmw_mode_select;	/* for analog tests (set to 0) */
   unsigned char	mmw_unused3[1];		/* unused */
-  unsigned char	mmw_fee_ctrl;		/* frequency eeprom control */
-#define	MMW_FEE_CTRL_PRE	0x10	/* Enable protected instructions */
-#define	MMW_FEE_CTRL_DWLD	0x08	/* Download eeprom to mmc */
-#define	MMW_FEE_CTRL_CMD	0x07	/* EEprom commands : */
+  unsigned char	mmw_fee_ctrl;		/* frequency EEPROM control */
+#define	MMW_FEE_CTRL_PRE	0x10	/* Enable protected instructions. */
+#define	MMW_FEE_CTRL_DWLD	0x08	/* Download EEPROM to mmc. */
+#define	MMW_FEE_CTRL_CMD	0x07	/* EEPROM commands:  */
 #define	MMW_FEE_CTRL_READ	0x06	/* Read */
 #define	MMW_FEE_CTRL_WREN	0x04	/* Write enable */
-#define	MMW_FEE_CTRL_WRITE	0x05	/* Write data to address */
-#define	MMW_FEE_CTRL_WRALL	0x04	/* Write data to all addresses */
+#define	MMW_FEE_CTRL_WRITE	0x05	/* Write data to address. */
+#define	MMW_FEE_CTRL_WRALL	0x04	/* Write data to all addresses. */
 #define	MMW_FEE_CTRL_WDS	0x04	/* Write disable */
 #define	MMW_FEE_CTRL_PRREAD	0x16	/* Read addr from protect register */
 #define	MMW_FEE_CTRL_PREN	0x14	/* Protect register enable */
-#define	MMW_FEE_CTRL_PRCLEAR	0x17	/* Unprotect all registers */
-#define	MMW_FEE_CTRL_PRWRITE	0x15	/* Write addr in protect register */
+#define	MMW_FEE_CTRL_PRCLEAR	0x17	/* Unprotect all registers. */
+#define	MMW_FEE_CTRL_PRWRITE	0x15	/* Write address in protect register */
 #define	MMW_FEE_CTRL_PRDS	0x14	/* Protect register disable */
-  /* Never issue this command (PRDS) : it's irreversible !!! */
+  /* Never issue the PRDS command:  it's irreversible! */
 
-  unsigned char	mmw_fee_addr;		/* EEprom address */
-#define	MMW_FEE_ADDR_CHANNEL	0xF0	/* Select the channel */
+  unsigned char	mmw_fee_addr;		/* EEPROM address */
+#define	MMW_FEE_ADDR_CHANNEL	0xF0	/* Select the channel. */
 #define	MMW_FEE_ADDR_OFFSET	0x0F	/* Offset in channel data */
 #define	MMW_FEE_ADDR_EN		0xC0	/* FEE_CTRL enable operations */
 #define	MMW_FEE_ADDR_DS		0x00	/* FEE_CTRL disable operations */
 #define	MMW_FEE_ADDR_ALL	0x40	/* FEE_CTRL all operations */
 #define	MMW_FEE_ADDR_CLEAR	0xFF	/* FEE_CTRL clear operations */
 
-  unsigned char	mmw_fee_data_l;		/* Write data to EEprom */
+  unsigned char	mmw_fee_data_l;		/* Write data to EEPROM. */
   unsigned char	mmw_fee_data_h;		/* high octet */
   unsigned char	mmw_ext_ant;		/* Setting for external antenna */
 #define	MMW_EXT_ANT_EXTANT	0x01	/* Select external antenna */
@@ -293,13 +293,13 @@
 #define	MMR_DCE_STATUS_LOOPT_IND	0x02	/* loop test indicated */
 #define	MMR_DCE_STATUS_TX_BUSY		0x04	/* transmitter on */
 #define	MMR_DCE_STATUS_JBR_EXPIRED	0x08	/* jabber timer expired */
-  unsigned char	mmr_dsp_id;		/* DSP id (AA = Daedalus rev A) */
+  unsigned char	mmr_dsp_id;		/* DSP ID (AA = Daedalus rev A) */
   unsigned char	mmr_unused2[2];		/* unused */
-  unsigned char	mmr_correct_nwid_l;	/* # of correct NWID's rxd (low) */
-  unsigned char	mmr_correct_nwid_h;	/* # of correct NWID's rxd (high) */
-  /* Warning : Read high order octet first !!! */
-  unsigned char	mmr_wrong_nwid_l;	/* # of wrong NWID's rxd (low) */
-  unsigned char	mmr_wrong_nwid_h;	/* # of wrong NWID's rxd (high) */
+  unsigned char	mmr_correct_nwid_l;	/* # of correct NWIDs rxd (low) */
+  unsigned char	mmr_correct_nwid_h;	/* # of correct NWIDs rxd (high) */
+  /* Warning:  read high-order octet first! */
+  unsigned char	mmr_wrong_nwid_l;	/* # of wrong NWIDs rxd (low) */
+  unsigned char	mmr_wrong_nwid_h;	/* # of wrong NWIDs rxd (high) */
   unsigned char	mmr_thr_pre_set;	/* level threshold preset */
 #define	MMR_THR_PRE_SET		0x3F		/* level threshold preset */
 #define	MMR_THR_PRE_SET_CUR	0x80		/* Current signal above it */
@@ -312,17 +312,17 @@
   unsigned char	mmr_sgnl_qual;		/* signal quality */
 #define	MMR_SGNL_QUAL		0x0F		/* signal quality */
 #define	MMR_SGNL_QUAL_ANT	0x80		/* current antenna used */
-  unsigned char	mmr_netw_id_l;		/* NWID low order byte ??? */
+  unsigned char	mmr_netw_id_l;		/* NWID low order byte (?) */
   unsigned char	mmr_unused3[3];		/* unused */
 
   /* 2.0 Hardware extension - frequency selection support */
-  unsigned char	mmr_fee_status;		/* Status of frequency eeprom */
-#define	MMR_FEE_STATUS_ID	0xF0		/* Modem revision id */
+  unsigned char	mmr_fee_status;		/* Status of frequency EEPROM */
+#define	MMR_FEE_STATUS_ID	0xF0		/* Modem revision ID */
 #define	MMR_FEE_STATUS_DWLD	0x08		/* Download in progress */
-#define	MMR_FEE_STATUS_BUSY	0x04		/* EEprom busy */
+#define	MMR_FEE_STATUS_BUSY	0x04		/* EEPROM busy */
   unsigned char	mmr_unused4[1];		/* unused */
-  unsigned char	mmr_fee_data_l;		/* Read data from eeprom (low) */
-  unsigned char	mmr_fee_data_h;		/* Read data from eeprom (high) */
+  unsigned char	mmr_fee_data_l;		/* Read data from EEPROM (low) */
+  unsigned char	mmr_fee_data_h;		/* Read data from EEPROM (high) */
 };
 
 #define	MMR_SIZE	36
diff -u --recursive --new-file v2.1.111/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h
--- v2.1.111/linux/drivers/net/wavelan.p.h	Tue May 13 22:41:12 1997
+++ linux/drivers/net/wavelan.p.h	Sun Jul 26 23:35:56 1998
@@ -1,79 +1,79 @@
 /*
- *	Wavelan ISA driver
+ *	WaveLAN ISA driver
  *
  *		Jean II - HPLB '96
  *
  * Reorganisation and extension of the driver.
  *
- * This file contain all definition and declarations necessary for the
- * wavelan isa driver. This file is a private header, so it should
- * be included only on wavelan.c !!!
+ * This file contains all definitions and declarations necessary for the
+ * WaveLAN ISA driver.  This file is a private header, so it should
+ * be included only in wavelan.c!
  */
 
 #ifndef WAVELAN_P_H
 #define WAVELAN_P_H
 
-/************************** DOCUMENTATION **************************/
+/************************** DOCUMENTATION ***************************/
 /*
- * This driver provide a Linux interface to the Wavelan ISA hardware
- * The Wavelan is a product of Lucent ("http://wavelan.netland.nl/").
+ * This driver provides a Linux interface to the WaveLAN ISA hardware.
+ * The WaveLAN is a product of Lucent (http://www.wavelan.com/).
  * This division was formerly part of NCR and then AT&T.
- * Wavelan are also distributed by DEC (RoamAbout), Digital Ocean and
- * Aironet (Arlan). If you have one of those product, you will need to
- * make some changes below...
- *
- * This driver is still a beta software. A lot of bugs have been corrected,
- * a lot of functionalities are implemented, the whole appear pretty stable,
- * but there is still some area of improvement (encryption, performance...).
- *
- * To know how to use this driver, read the NET3 HOWTO.
- * If you want to exploit the many other fonctionalities, look comments
- * in the code...
+ * WaveLANs are also distributed by DEC (RoamAbout), Digital Ocean and
+ * Aironet (Arlan).  If you have one of those products, you will need to
+ * make some changes below.
+ *
+ * This driver is still beta software.  A lot of bugs have been corrected,
+ * a lot of functionality is implemented, and the whole appears stable,
+ * but there is still room for improvement (encryption, performance).
+ *
+ * To learn how to use this driver, read the NET3 HOWTO.
+ * If you want to exploit the many other functionalities, read the comments
+ * in the code.
  *
- * This driver is the result of the effort of many peoples (see below).
+ * This driver is the result of the effort of many people (see below).
  */
 
 /* ------------------------ SPECIFIC NOTES ------------------------ */
 /*
- * wavelan.o is darn too big
- * -------------------------
- *	That's true ! There is a very simple way to reduce the driver
- *	object by 33% (yes !). Comment out the following line :
+ * wavelan.o is too darned big
+ * ---------------------------
+ *	That's true!  There is a very simple way to reduce the driver
+ *	object by 33%!  Comment out the following line:
  *		#include <linux/wireless.h>
  *
- * MAC address and hardware detection :
- * ----------------------------------
- *	The detection code of the wavelan chech that the first 3
- *	octets of the MAC address fit the company code. This type of
- *	detection work well for AT&T cards (because the AT&T code is
+ * MAC address and hardware detection:
+ * -----------------------------------
+ *	The detection code for the WaveLAN checks that the first three
+ *	octets of the MAC address fit the company code.  This type of
+ *	detection works well for AT&T cards (because the AT&T code is
  *	hardcoded in wavelan.h), but of course will fail for other
- *	manufacturer.
+ *	manufacturers.
  *
- *	If you are sure that your card is derived from the wavelan,
- *	here is the way to configure it :
+ *	If you are sure that your card is derived from the WaveLAN,
+ *	here is the way to configure it:
  *	1) Get your MAC address
- *		a) With your card utilities (wfreqsel, instconf, ...)
- *		b) With the driver :
+ *		a) With your card utilities (wfreqsel, instconf, etc.)
+ *		b) With the driver:
  *			o compile the kernel with DEBUG_CONFIG_INFO enabled
  *			o Boot and look the card messages
  *	2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h)
- *	3) Compile & verify
- *	4) Send me the MAC code - I will include it in the next version...
+ *	3) Compile and verify
+ *	4) Send me the MAC code.  I will include it in the next version.
  *
- * "CU Inactive" message at boot up :
+ * "CU Inactive" message at boot up:
  * -----------------------------------
- *	It seem that there is some weird timings problems with the
- *	Intel microcontroler. In fact, this message is triggered by a
- *	bad reading of the on board ram the first time we read the
- *	control block. If you ignore this message, all is ok (but in
- *	fact, currently, it reset the wavelan hardware).
+ *	It seems that there is some weird timing problem with the
+ *	Intel microcontroller.  In fact, this message is triggered by a
+ *	bad reading of the onboard RAM the first time we read the
+ *	control block.  If you ignore this message, all is OK (but in
+ *	fact, currently, it resets the WaveLAN hardware).
  *
- *	To get rid of that problem, there is two solution. The first
+ *	There are two ways to get rid of that problem.  The first
  *	is to add a dummy read of the scb at the end of
- *	wv_82586_config. The second is to add the timers
+ *	wv_82586_config.  The second is to add the timers
  *	wv_synchronous_cmd and wv_ack (the udelay just after the
- *	waiting loops - seem that the controler is not totally ready
- *	when it say it is !).
+ *	waiting loops--it seems that the controller is not totally ready
+ *	when it says it is).
  *
  *	In the current code, I use the second solution (to be
  *	consistent with the original solution of Bruce Janson).
@@ -81,10 +81,10 @@
 
 /* --------------------- WIRELESS EXTENSIONS --------------------- */
 /*
- * This driver is the first one to support "wireless extensions".
- * This set of extensions provide you some way to control the wireless
- * caracteristics of the hardware in a standard way and support for
- * applications for taking advantage of it (like Mobile IP).
+ * This driver is the first to support "wireless extensions".
+ * This set of extensions provides a standard way to control the wireless
+ * characteristics of the hardware.  Applications such as mobile IP may
+ * take advantage of it.
  *
  * You will need to enable the CONFIG_NET_RADIO define in the kernel
  * configuration to enable the wireless extensions (this is the one
@@ -96,64 +96,64 @@
 
 /* ---------------------------- FILES ---------------------------- */
 /*
- * wavelan.c :		The actual code for the driver - C functions
+ * wavelan.c:		actual code for the driver:  C functions
  *
- * wavelan.p.h :	Private header : local types / vars for the driver
+ * wavelan.p.h:		private header:  local types and variables for driver
  *
- * wavelan.h :		Description of the hardware interface & structs
+ * wavelan.h:		description of the hardware interface and structs
  *
- * i82586.h :		Description if the Ethernet controler
+ * i82586.h:		description of the Ethernet controller
  */
 
 /* --------------------------- HISTORY --------------------------- */
 /*
- * (Made with information in drivers headers. It may not be accurate,
- * and I garantee nothing except my best effort...)
+ * This is based on information in the drivers' headers. It may not be
+ * accurate, and I guarantee only my best effort.
  *
- * The history of the Wavelan drivers is as complicated as history of
- * the Wavelan itself (NCR -> AT&T -> Lucent).
+ * The history of the WaveLAN drivers is as complicated as the history of
+ * the WaveLAN itself (NCR -> AT&T -> Lucent).
  *
- * All started with Anders Klemets <klemets@paul.rutgers.edu>,
- * writting a Wavelan ISA driver for the MACH microkernel. Girish
+ * It all started with Anders Klemets <klemets@paul.rutgers.edu>
+ * writing a WaveLAN ISA driver for the Mach microkernel.  Girish
  * Welling <welling@paul.rutgers.edu> had also worked on it.
- * Keith Moore modify this for the Pcmcia hardware.
+ * Keith Moore modified this for the PCMCIA hardware.
  * 
- * Robert Morris <rtm@das.harvard.edu> port these two drivers to BSDI
- * and add specific Pcmcia support (there is currently no equivalent
- * of the PCMCIA package under BSD...).
+ * Robert Morris <rtm@das.harvard.edu> ported these two drivers to BSDI
+ * and added specific PCMCIA support (there is currently no equivalent
+ * of the PCMCIA package under BSD).
  *
- * Jim Binkley <jrb@cs.pdx.edu> port both BSDI drivers to freeBSD.
+ * Jim Binkley <jrb@cs.pdx.edu> ported both BSDI drivers to FreeBSD.
  *
- * Bruce Janson <bruce@cs.usyd.edu.au> port the BSDI ISA driver to Linux.
+ * Bruce Janson <bruce@cs.usyd.edu.au> ported the BSDI ISA driver to Linux.
  *
- * Anthony D. Joseph <adj@lcs.mit.edu> started modify Bruce driver
+ * Anthony D. Joseph <adj@lcs.mit.edu> started to modify Bruce's driver
  * (with help of the BSDI PCMCIA driver) for PCMCIA.
- * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work.
+ * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished this work.
  * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
- * correctly 2.00 cards (2.4 GHz with frequency selection).
+ * 2.00 cards correctly (2.4 GHz with frequency selection).
  * David Hinds <dhinds@hyper.stanford.edu> integrated the whole in his
- * Pcmcia package (+ bug corrections).
+ * PCMCIA package (and bug corrections).
  *
  * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
- * patchs to the Pcmcia driver. After, I added code in the ISA driver
+ * patches to the PCMCIA driver.  Later, I added code in the ISA driver
  * for Wireless Extensions and full support of frequency selection
- * cards. Then, I've done the same to the Pcmcia driver + some
- * reorganisation. Finally, I came back to the ISA driver to
- * upgrade it at the same level as the Pcmcia one and reorganise
- * the code
+ * cards.  Then, I did the same to the PCMCIA driver, and did some
+ * reorganisation.  Finally, I came back to the ISA driver to
+ * upgrade it at the same level as the PCMCIA one and reorganise
+ * the code.
  * Loeke Brederveld <lbrederv@wavelan.com> from Lucent has given me
- * much needed informations on the Wavelan hardware.
+ * much needed information on the WaveLAN hardware.
  */
 
-/* The original copyrights and litteratures mention others names and
- * credits. I don't know what there part in this development was...
+/* The original copyrights and literature mention others' names and
+ * credits.  I don't know what their part in this development was.
  */
 
-/* By the way : for the copyright & legal stuff :
- * Almost everybody wrote code under GNU or BSD license (or alike),
- * and want that their original copyright remain somewhere in the
+/* By the way, for the copyright and legal stuff:
+ * almost everybody wrote code under the GNU or BSD license (or similar),
+ * and want their original copyright to remain somewhere in the
  * code (for myself, I go with the GPL).
- * Nobody want to take responsibility for anything, except the fame...
+ * Nobody wants to take responsibility for anything, except the fame.
  */
 
 /* --------------------------- CREDITS --------------------------- */
@@ -162,121 +162,120 @@
  * Linux operating system.
  * It is based on other device drivers and information
  * either written or supplied by:
- *	Ajay Bakre (bakre@paul.rutgers.edu),
- *	Donald Becker (becker@cesdis.gsfc.nasa.gov),
- *	Loeke Brederveld (Loeke.Brederveld@Utrecht.NCR.com),
+ *	Ajay Bakre <bakre@paul.rutgers.edu>,
+ *	Donald Becker <becker@cesdis.gsfc.nasa.gov>,
+ *	Loeke Brederveld <Loeke.Brederveld@Utrecht.NCR.com>,
  *	Brent Elphick <belphick@uwaterloo.ca>,
- *	Anders Klemets (klemets@it.kth.se),
- *	Vladimir V. Kolpakov (w@stier.koenig.ru),
- *	Marc Meertens (Marc.Meertens@Utrecht.NCR.com),
- *	Pauline Middelink (middelin@polyware.iaf.nl),
- *	Robert Morris (rtm@das.harvard.edu),
- *	Jean Tourrilhes (jt@hplb.hpl.hp.com),
- *	Girish Welling (welling@paul.rutgers.edu),
+ *	Anders Klemets <klemets@it.kth.se>,
+ *	Vladimir V. Kolpakov <w@stier.koenig.ru>,
+ *	Marc Meertens <Marc.Meertens@Utrecht.NCR.com>,
+ *	Pauline Middelink <middelin@polyware.iaf.nl>,
+ *	Robert Morris <rtm@das.harvard.edu>,
+ *	Jean Tourrilhes <jt@hplb.hpl.hp.com>,
+ *	Girish Welling <welling@paul.rutgers.edu>,
  *	Clark Woodworth <clark@hiway1.exit109.com>
- *	Yongguang Zhang <ygz@isl.hrl.hac.com>...
+ *	Yongguang Zhang <ygz@isl.hrl.hac.com>
  *
  * Thanks go also to:
- *	James Ashton (jaa101@syseng.anu.edu.au),
- *	Alan Cox (iialan@iiit.swan.ac.uk),
- *	Allan Creighton (allanc@cs.usyd.edu.au),
- *	Matthew Geier (matthew@cs.usyd.edu.au),
- *	Remo di Giovanni (remo@cs.usyd.edu.au),
- *	Eckhard Grah (grah@wrcs1.urz.uni-wuppertal.de),
- *	Vipul Gupta (vgupta@cs.binghamton.edu),
- *	Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
- *	Tim Nicholson (tim@cs.usyd.edu.au),
- *	Ian Parkin (ian@cs.usyd.edu.au),
- *	John Rosenberg (johnr@cs.usyd.edu.au),
- *	George Rossi (george@phm.gov.au),
- *	Arthur Scott (arthur@cs.usyd.edu.au),
+ *	James Ashton <jaa101@syseng.anu.edu.au>,
+ *	Alan Cox <iialan@iiit.swan.ac.uk>,
+ *	Allan Creighton <allanc@cs.usyd.edu.au>,
+ *	Matthew Geier <matthew@cs.usyd.edu.au>,
+ *	Remo di Giovanni <remo@cs.usyd.edu.au>,
+ *	Eckhard Grah <grah@wrcs1.urz.uni-wuppertal.de>,
+ *	Vipul Gupta <vgupta@cs.binghamton.edu>,
+ *	Mark Hagan <mhagan@wtcpost.daytonoh.NCR.COM>,
+ *	Tim Nicholson <tim@cs.usyd.edu.au>,
+ *	Ian Parkin <ian@cs.usyd.edu.au>,
+ *	John Rosenberg <johnr@cs.usyd.edu.au>,
+ *	George Rossi <george@phm.gov.au>,
+ *	Arthur Scott <arthur@cs.usyd.edu.au>,
  *	Stanislav Sinyagin <stas@isf.ru>
- *	Peter Storey,
- * for their assistance and advice.
+ *	and Peter Storey for their assistance and advice.
  *
  * Additional Credits:
  *
- * My developpement has been done under Linux 2.0.x (Debian 1.1) with
+ *	My development has been done under Linux 2.0.x (Debian 1.1) with
  *	an HP Vectra XP/60.
  *
  */
 
 /* ------------------------- IMPROVEMENTS ------------------------- */
 /*
- * I proudly present :
+ * I proudly present:
  *
- * Changes mades in first pre-release :
+ * Changes made in first pre-release:
  * ----------------------------------
- *	- Reorganisation of the code, function name change
- *	- Creation of private header (wavelan.p.h)
- *	- Reorganised debug messages
- *	- More comments, history, ...
- *	- mmc_init : configure the PSA if not done
- *	- mmc_init : correct default value of level threshold for pcmcia
- *	- mmc_init : 2.00 detection better code for 2.00 init
+ *	- reorganisation of the code, function name change
+ *	- creation of private header (wavelan.p.h)
+ *	- reorganised debug messages
+ *	- more comments, history, etc.
+ *	- mmc_init:  configure the PSA if not done
+ *	- mmc_init:  correct default value of level threshold for PCMCIA
+ *	- mmc_init:  2.00 detection better code for 2.00 initialization
  *	- better info at startup
- *	- irq setting (note : this setting is permanent...)
- *	- Watchdog : change strategy (+ solve module removal problems)
- *	- add wireless extensions (ioctl & get_wireless_stats)
+ *	- IRQ setting (note:  this setting is permanent)
+ *	- watchdog:  change strategy (and solve module removal problems)
+ *	- add wireless extensions (ioctl and get_wireless_stats)
  *	  get/set nwid/frequency on fly, info for /proc/net/wireless
- *	- More wireless extension : SETSPY and GETSPY
- *	- Make wireless extensions optional
- *	- Private ioctl to set/get quality & level threshold, histogram
- *	- Remove /proc/net/wavelan
- *	- Supress useless stuff from lp (net_local)
+ *	- more wireless extensions:  SETSPY and GETSPY
+ *	- make wireless extensions optional
+ *	- private ioctl to set/get quality and level threshold, histogram
+ *	- remove /proc/net/wavelan
+ *	- suppress useless stuff from lp (net_local)
  *	- kernel 2.1 support (copy_to/from_user instead of memcpy_to/fromfs)
- *	- Add message level (debug stuff in /var/adm/debug & errors not
+ *	- add message level (debug stuff in /var/adm/debug and errors not
  *	  displayed at console and still in /var/adm/messages)
  *	- multi device support
- *	- Start fixing the probe (init code)
- *	- More inlines
+ *	- start fixing the probe (init code)
+ *	- more inlines
  *	- man page
- *	- Lot of others minor details & cleanups
+ *	- many other minor details and cleanups
  *
- * Changes made in second pre-release :
- * ----------------------------------
- *	- Cleanup init code (probe & module init)
- *	- Better multi device support (module)
- *	- name assignement (module)
- *
- * Changes made in third pre-release :
- * ---------------------------------
- *	- Be more conservative on timers
- *	- Preliminary support for multicast (I still lack some details...)
+ * Changes made in second pre-release:
+ * -----------------------------------
+ *	- clean up init code (probe and module init)
+ *	- better multiple device support (module)
+ *	- name assignment (module)
  *
- * Changes made in fourth pre-release :
+ * Changes made in third pre-release:
  * ----------------------------------
+ *	- be more conservative on timers
+ *	- preliminary support for multicast (I still lack some details)
+ *
+ * Changes made in fourth pre-release:
+ * -----------------------------------
  *	- multicast (revisited and finished)
- *	- Avoid reset in set_multicast_list (a really big hack)
- *	  if somebody could apply this code for other i82586 based driver...
- *	- Share on board memory 75% RU / 25% CU (instead of 50/50)
+ *	- avoid reset in set_multicast_list (a really big hack)
+ *	  if somebody could apply this code for other i82586 based drivers
+ *	- share onboard memory 75% RU and 25% CU (instead of 50/50)
  *
- * Changes made for release in 2.1.15 :
- * ----------------------------------
- *	- Change the detection code for multi manufacturer code support
+ * Changes made for release in 2.1.15:
+ * -----------------------------------
+ *	- change the detection code for multi manufacturer code support
  *
- * Changes made for release in 2.1.17 :
- * ----------------------------------
- *	- Update to wireless extensions changes
- *	- Silly bug in card initial configuration (psa_conf_status)
+ * Changes made for release in 2.1.17:
+ * -----------------------------------
+ *	- update to wireless extensions changes
+ *	- silly bug in card initial configuration (psa_conf_status)
  *
- * Changes made for release in 2.1.27 & 2.0.30 :
- * -------------------------------------------
- *	- Small bug in debug code (probably not the last one...)
- *	- Remove extern kerword for wavelan_probe()
- *	- Level threshold is now a standard wireless extension (version 4 !)
+ * Changes made for release in 2.1.27 & 2.0.30:
+ * --------------------------------------------
+ *	- small bug in debug code (probably not the last one...)
+ *	- remove extern keyword for wavelan_probe()
+ *	- level threshold is now a standard wireless extension (version 4 !)
  *	- modules parameters types (new module interface)
  *
- * Changes made for release in 2.1.36 :
- * ----------------------------------
+ * Changes made for release in 2.1.36:
+ * -----------------------------------
  *	- byte count stats (courtesy of David Hinds)
- *	- Remove dev_tint stuff (courtesy of David Hinds)
- *	- Encryption setting from Brent Elphick (thanks a lot !)
+ *	- remove dev_tint stuff (courtesy of David Hinds)
+ *	- encryption setting from Brent Elphick (thanks a lot!)
  *	- 'ioaddr' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin)
  *
- * Wishes & dreams :
- * ---------------
- *	- Roaming
+ * Wishes & dreams:
+ * ----------------
+ *	- roaming
  */
 
 /***************************** INCLUDES *****************************/
@@ -309,52 +308,52 @@
 
 #include <linux/wireless.h>		/* Wireless extensions */
 
-/* Wavelan declarations */
+/* WaveLAN declarations */
 #include	"i82586.h"
 #include	"wavelan.h"
 
 /****************************** DEBUG ******************************/
 
-#undef DEBUG_MODULE_TRACE	/* Module insertion/removal */
-#undef DEBUG_CALLBACK_TRACE	/* Calls made by Linux */
-#undef DEBUG_INTERRUPT_TRACE	/* Calls to handler */
-#undef DEBUG_INTERRUPT_INFO	/* type of interrupt & so on */
+#undef DEBUG_MODULE_TRACE	/* module insertion/removal */
+#undef DEBUG_CALLBACK_TRACE	/* calls made by Linux */
+#undef DEBUG_INTERRUPT_TRACE	/* calls to handler */
+#undef DEBUG_INTERRUPT_INFO	/* type of interrupt and so on */
 #define DEBUG_INTERRUPT_ERROR	/* problems */
-#undef DEBUG_CONFIG_TRACE	/* Trace the config functions */
-#undef DEBUG_CONFIG_INFO	/* What's going on... */
-#define DEBUG_CONFIG_ERRORS	/* Errors on configuration */
-#undef DEBUG_TX_TRACE		/* Transmission calls */
-#undef DEBUG_TX_INFO		/* Header of the transmited packet */
+#undef DEBUG_CONFIG_TRACE	/* Trace the config functions. */
+#undef DEBUG_CONFIG_INFO	/* what's going on */
+#define DEBUG_CONFIG_ERRORS	/* errors on configuration */
+#undef DEBUG_TX_TRACE		/* transmission calls */
+#undef DEBUG_TX_INFO		/* header of the transmitted packet */
 #define DEBUG_TX_ERROR		/* unexpected conditions */
-#undef DEBUG_RX_TRACE		/* Transmission calls */
-#undef DEBUG_RX_INFO		/* Header of the transmited packet */
+#undef DEBUG_RX_TRACE		/* transmission calls */
+#undef DEBUG_RX_INFO		/* header of the transmitted packet */
 #define DEBUG_RX_ERROR		/* unexpected conditions */
-#undef DEBUG_PACKET_DUMP	16	/* Dump packet on the screen */
-#undef DEBUG_IOCTL_TRACE	/* Misc call by Linux */
-#undef DEBUG_IOCTL_INFO		/* Various debug info */
-#define DEBUG_IOCTL_ERROR	/* What's going wrong */
-#define DEBUG_BASIC_SHOW	/* Show basic startup info */
-#undef DEBUG_VERSION_SHOW	/* Print version info */
-#undef DEBUG_PSA_SHOW		/* Dump psa to screen */
-#undef DEBUG_MMC_SHOW		/* Dump mmc to screen */
-#undef DEBUG_SHOW_UNUSED	/* Show also unused fields */
-#undef DEBUG_I82586_SHOW	/* Show i82586 status */
-#undef DEBUG_DEVICE_SHOW	/* Show device parameters */
-
-/* Options : */
-#define USE_PSA_CONFIG		/* Use info from the PSA */
-#define IGNORE_NORMAL_XMIT_ERRS	/* Don't bother with normal conditions */
-#undef STRUCT_CHECK		/* Verify padding of structures */
-#undef PSA_CRC			/* Check CRC in PSA */
-#undef OLDIES			/* Old code (to redo) */
-#undef RECORD_SNR		/* To redo */
-#undef EEPROM_IS_PROTECTED	/* Doesn't seem to be necessary */
-#define MULTICAST_AVOID		/* Avoid extra multicast (I'm sceptical) */
-
-#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
-/* Warning : these stuff will slow down the driver... */
-#define WIRELESS_SPY		/* Enable spying addresses */
-#undef HISTOGRAM		/* Enable histogram of sig level... */
+#undef DEBUG_PACKET_DUMP	16	/* Dump packet on the screen. */
+#undef DEBUG_IOCTL_TRACE	/* misc. call by Linux */
+#undef DEBUG_IOCTL_INFO		/* various debugging info */
+#define DEBUG_IOCTL_ERROR	/* what's going wrong */
+#define DEBUG_BASIC_SHOW	/* Show basic startup info. */
+#undef DEBUG_VERSION_SHOW	/* Print version info. */
+#undef DEBUG_PSA_SHOW		/* Dump PSA to screen. */
+#undef DEBUG_MMC_SHOW		/* Dump mmc to screen. */
+#undef DEBUG_SHOW_UNUSED	/* Show unused fields too. */
+#undef DEBUG_I82586_SHOW	/* Show i82586 status. */
+#undef DEBUG_DEVICE_SHOW	/* Show device parameters. */
+
+/* Options */
+#define USE_PSA_CONFIG		/* Use info from the PSA. */
+#define IGNORE_NORMAL_XMIT_ERRS	/* Don't bother with normal conditions. */
+#undef STRUCT_CHECK		/* Verify padding of structures. */
+#undef PSA_CRC			/* Check CRC in PSA. */
+#undef OLDIES			/* old code (to redo) */
+#undef RECORD_SNR		/* to redo */
+#undef EEPROM_IS_PROTECTED	/* doesn't seem to be necessary */
+#define MULTICAST_AVOID		/* Avoid extra multicast (I'm sceptical). */
+
+#ifdef WIRELESS_EXT	/* If wireless extensions exist in the kernel */
+/* Warning:  this stuff will slow down the driver. */
+#define WIRELESS_SPY		/* Enable spying addresses. */
+#undef HISTOGRAM		/* Enable histogram of signal level. */
 #endif
 
 /************************ CONSTANTS & MACROS ************************/
@@ -364,7 +363,7 @@
 #endif
 
 /* Watchdog temporisation */
-#define	WATCHDOG_JIFFIES	32	/* TODO: express in HZ. */
+#define	WATCHDOG_JIFFIES	32	/* TODO:  express in HZ. */
 
 /* Macro to get the number of elements in an array */
 #define	NELS(a)				(sizeof(a) / sizeof(a[0]))
@@ -396,23 +395,23 @@
 /*
  * Static specific data for the interface.
  *
- * For each network interface, Linux keep data in two structure. "device"
- * keep the generic data (same format for everybody) and "net_local" keep
- * the additional specific data.
+ * For each network interface, Linux keeps data in two structures:  "device"
+ * keeps the generic data (same format for everybody) and "net_local" keeps
+ * additional specific data.
  * Note that some of this specific data is in fact generic (en_stats, for
  * example).
  */
 struct net_local
 {
-  net_local *	next;		/* Linked list of the devices */
-  device *	dev;		/* Reverse link... */
+  net_local *	next;		/* linked list of the devices */
+  device *	dev;		/* reverse link */
   en_stats	stats;		/* Ethernet interface statistics */
-  int		nresets;	/* Number of hw resets */
-  u_char	reconfig_82586;	/* Need to reconfigure the controler */
-  u_char	promiscuous;	/* Promiscuous mode */
-  int		mc_count;	/* Number of multicast addresses */
-  timer_list	watchdog;	/* To avoid blocking state */
-  u_short	hacr;		/* Current host interface state */
+  int		nresets;	/* number of hardware resets */
+  u_char	reconfig_82586;	/* We need to reconfigure the controller. */
+  u_char	promiscuous;	/* promiscuous mode */
+  int		mc_count;	/* number of multicast addresses */
+  timer_list	watchdog;	/* to avoid blocking state */
+  u_short	hacr;		/* current host interface state */
 
   int		tx_n_in_use;
   u_short	rx_head;
@@ -421,82 +420,83 @@
   u_short	tx_first_in_use;
 
 #ifdef WIRELESS_EXT
-  iw_stats	wstats;		/* Wireless specific stats */
+  iw_stats	wstats;		/* Wireless-specific statistics */
 #endif
 
 #ifdef WIRELESS_SPY
-  int		spy_number;		/* Number of addresses to spy */
-  mac_addr	spy_address[IW_MAX_SPY];	/* The addresses to spy */
-  iw_qual	spy_stat[IW_MAX_SPY];		/* Statistics gathered */
+  int		spy_number;			/* number of addresses to spy */
+  mac_addr	spy_address[IW_MAX_SPY];	/* the addresses to spy */
+  iw_qual	spy_stat[IW_MAX_SPY];		/* statistics gathered */
 #endif	/* WIRELESS_SPY */
+
 #ifdef HISTOGRAM
-  int		his_number;		/* Number of intervals */
-  u_char	his_range[16];		/* Boundaries of interval ]n-1; n] */
-  u_long	his_sum[16];		/* Sum in interval */
+  int		his_number;		/* number of intervals */
+  u_char	his_range[16];		/* boundaries of interval ]n-1; n] */
+  u_long	his_sum[16];		/* sum in interval */
 #endif	/* HISTOGRAM */
 };
 
 /**************************** PROTOTYPES ****************************/
 
-/* ----------------------- MISC SUBROUTINES ------------------------ */
+/* ----------------------- MISC. SUBROUTINES ------------------------ */
 static inline unsigned long	/* flags */
 	wv_splhi(void);		/* Disable interrupts */
 static inline void
-	wv_splx(unsigned long);	/* ReEnable interrupts : flags */
+	wv_splx(unsigned long);	/* Enable interrupts:  flags */
 static u_char
 	wv_irq_to_psa(int);
 static int
 	wv_psa_to_irq(u_char);
 /* ------------------- HOST ADAPTER SUBROUTINES ------------------- */
 static inline u_short		/* data */
-	hasr_read(u_long);	/* Read the host interface : base address */
+	hasr_read(u_long);	/* Read the host interface:  base address */
 static inline void
-	hacr_write(u_long,	/* Write to host interface : base address */
+	hacr_write(u_long,	/* Write to host interface:  base address */
 		   u_short),	/* data */
 	hacr_write_slow(u_long,
 		   u_short),
 	set_chan_attn(u_long,	/* ioaddr */
-		      u_short),	/* hacr */
+		      u_short),	/* hacr   */
 	wv_hacr_reset(u_long),	/* ioaddr */
 	wv_16_off(u_long,	/* ioaddr */
-		  u_short),	/* hacr */
+		  u_short),	/* hacr   */
 	wv_16_on(u_long,	/* ioaddr */
-		 u_short),	/* hacr */
+		 u_short),	/* hacr   */
 	wv_ints_off(device *),
 	wv_ints_on(device *);
 /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
 static void
-	psa_read(u_long,	/* Read the Parameter Storage Area */
+	psa_read(u_long,	/* Read the Parameter Storage Area. */
 		 u_short,	/* hacr */
 		 int,		/* offset in PSA */
 		 u_char *,	/* buffer to fill */
 		 int),		/* size to read */
-	psa_write(u_long, 	/* Write to the PSA */
+	psa_write(u_long, 	/* Write to the PSA. */
 		  u_short,	/* hacr */
-		  int,		/* Offset in psa */
-		  u_char *,	/* Buffer in memory */
-		  int);		/* Length of buffer */
+		  int,		/* offset in PSA */
+		  u_char *,	/* buffer in memory */
+		  int);		/* length of buffer */
 static inline void
-	mmc_out(u_long,		/* Write 1 byte to the Modem Manag Control */
+	mmc_out(u_long,		/* Write 1 byte to the Modem Manag Control. */
 		u_short,
 		u_char),
-	mmc_write(u_long,	/* Write n bytes to the MMC */
+	mmc_write(u_long,	/* Write n bytes to the MMC. */
 		  u_char,
 		  u_char *,
 		  int);
-static inline u_char		/* Read 1 byte from the MMC */
+static inline u_char		/* Read 1 byte from the MMC. */
 	mmc_in(u_long,
 	       u_short);
 static inline void
-	mmc_read(u_long,	/* Read n bytes from the MMC */
+	mmc_read(u_long,	/* Read n bytes from the MMC. */
 		 u_char,
 		 u_char *,
 		 int),
-	fee_wait(u_long,	/* Wait for frequency EEprom : base address */
-		 int,		/* Base delay to wait for */
-		 int);		/* Number of time to wait */
+	fee_wait(u_long,	/* Wait for frequency EEPROM:  base address */
+		 int,		/* base delay to wait for */
+		 int);		/* time to wait */
 static void
-	fee_read(u_long,	/* Read the frequency EEprom : base address */
+	fee_read(u_long,	/* Read the frequency EEPROM:  base address */
 		 u_short,	/* destination offset */
 		 u_short *,	/* data buffer */
 		 int);		/* number of registers */
@@ -539,60 +539,59 @@
 	wavelan_set_multicast_list(device *);
 /* ----------------------- PACKET RECEPTION ----------------------- */
 static inline void
-	wv_packet_read(device *,	/* Read a packet from a frame */
+	wv_packet_read(device *,	/* Read a packet from a frame. */
 		       u_short,
 		       int),
-	wv_receive(device *);	/* Read all packets waiting */
+	wv_receive(device *);	/* Read all packets waiting. */
 /* --------------------- PACKET TRANSMISSION --------------------- */
 static inline void
-	wv_packet_write(device *,	/* Write a packet to the Tx buffer */
+	wv_packet_write(device *,	/* Write a packet to the Tx buffer. */
 			void *,
 			short);
 static int
-	wavelan_packet_xmit(struct sk_buff *,	/* Send a packet */
+	wavelan_packet_xmit(struct sk_buff *,	/* Send a packet. */
 			    device *);
 /* -------------------- HARDWARE CONFIGURATION -------------------- */
 static inline int
-	wv_mmc_init(device *),		/* Initialize the modem */
-	wv_ru_start(device *),		/* Start the i82586 receiver unit */
-	wv_cu_start(device *),		/* Start the i82586 command unit */
-	wv_82586_start(device *);	/* Start the i82586 */
+	wv_mmc_init(device *),		/* Initialize the modem. */
+	wv_ru_start(device *),		/* Start the i82586 receiver unit. */
+	wv_cu_start(device *),		/* Start the i82586 command unit. */
+	wv_82586_start(device *);	/* Start the i82586. */
 static void
-	wv_82586_config(device *);	/* Configure the i82586 */
+	wv_82586_config(device *);	/* Configure the i82586. */
 static inline void
 	wv_82586_stop(device *);
 static int
-	wv_hw_reset(device *),		/* Reset the wavelan hardware */
+	wv_hw_reset(device *),		/* Reset the WaveLAN hardware. */
 	wv_check_ioaddr(u_long,		/* ioaddr */
 			u_char *);	/* mac address (read) */
 /* ---------------------- INTERRUPT HANDLING ---------------------- */
 static void
-	wavelan_interrupt(int,		/* Interrupt handler */
+	wavelan_interrupt(int,		/* interrupt handler */
 			  void *,
 			  struct pt_regs *);
 static void
-	wavelan_watchdog(u_long);	/* Transmission watchdog */
+	wavelan_watchdog(u_long);	/* transmission watchdog */
 /* ------------------- CONFIGURATION CALLBACKS ------------------- */
 static int
-	wavelan_open(device *),		/* Open the device */
-	wavelan_close(device *),	/* Close the device */
-	wavelan_config(device *);	/* Configure one device */
+	wavelan_open(device *),		/* Open the device. */
+	wavelan_close(device *),	/* Close the device. */
+	wavelan_config(device *);	/* Configure one device. */
 extern int
-	wavelan_probe(device *);	/* See Space.c */
+	wavelan_probe(device *);	/* See Space.c. */
 
 /**************************** VARIABLES ****************************/
 
 /*
- * This is the root of the linked list of wavelan drivers
+ * This is the root of the linked list of WaveLAN drivers
  * It is use to verify that we don't reuse the same base address
- * for two differents drivers and to make the cleanup when
- * removing the module.
+ * for two different drivers and to clean up when removing the module.
  */
 static net_local *	wavelan_list	= (net_local *) NULL;
 
 /*
- * This table is used to translate the psa value to irq number
- * and vice versa...
+ * This table is used to translate the PSA value to IRQ number
+ * and vice versa.
  */
 static u_char	irqvals[]	=
 {
@@ -603,7 +602,7 @@
 };
 
 /*
- * Table of the available i/o address (base address) for wavelan
+ * Table of the available I/O addresses (base addresses) for WaveLAN
  */
 static unsigned short	iobase[]	=
 {
@@ -612,7 +611,7 @@
    * controllers.
    * Leave out the others too -- we will always use 0x390 and leave
    * 0x300 for the Ethernet device.
-   * Jean II : 0x3E0 is really fine as well...
+   * Jean II:  0x3E0 is fine as well.
    */
   0x300, 0x390, 0x3E0, 0x3C0
 #endif	/* 0 */
diff -u --recursive --new-file v2.1.111/linux/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c
--- v2.1.111/linux/drivers/pci/oldproc.c	Thu Jul 16 18:09:26 1998
+++ linux/drivers/pci/oldproc.c	Mon Jul 27 11:44:57 1998
@@ -1,5 +1,5 @@
 /*
- *	$Id: oldproc.c,v 1.13 1998/05/07 20:49:50 davem Exp $
+ *	$Id: oldproc.c,v 1.16 1998/07/19 17:50:18 davem Exp $
  *
  *	Backward-compatible procfs interface for PCI.
  *
@@ -255,6 +255,7 @@
 	DEVICE( DATABOOK,      	DATABOOK_87144,	"DB87144"),
 	DEVICE( PLX,		PLX_9080,	"PCI9080 I2O"),
 	DEVICE( MADGE,		MADGE_MK2,	"Smart 16/4 BM Mk2 Ringnode"),
+	DEVICE( MADGE,		MADGE_C155S,	"Collage 155 Server"),
 	DEVICE( 3COM,		3COM_3C339,	"3C339 TokenRing"),
 	DEVICE( 3COM,		3COM_3C590,	"3C590 10bT"),
 	DEVICE( 3COM,		3COM_3C595TX,	"3C595 100bTX"),
@@ -433,6 +434,7 @@
 	DEVICE( SATSAGEM,	SATSAGEM_TELSATTURBO,"Telsat Turbo DVB"),
 	DEVICE( HUGHES,		HUGHES_DIRECPC,	"DirecPC"),
 	DEVICE( ENSONIQ,	ENSONIQ_AUDIOPCI,"AudioPCI"),
+	DEVICE( ALTEON,		ALTEON_ACENIC,"AceNIC"),
 	DEVICE( PICTUREL,	PICTUREL_PCIVST,"PCIVST"),
 	DEVICE( NVIDIA_SGS,	NVIDIA_SGS_RIVA128,	"Riva 128"),
 	DEVICE( CBOARDS,	CBOARDS_DAS1602_16,"DAS1602/16"),
@@ -746,6 +748,7 @@
 	      case PCI_VENDOR_ID_COMPEX:	return "Compex";
 	      case PCI_VENDOR_ID_RP:		return "Comtrol";
 	      case PCI_VENDOR_ID_CYCLADES:	return "Cyclades";
+	      case PCI_VENDOR_ID_ESSENTIAL:	return "Essential Communications";
 	      case PCI_VENDOR_ID_O2:		return "O2 Micro";
 	      case PCI_VENDOR_ID_3DFX:		return "3Dfx";
 	      case PCI_VENDOR_ID_SIGMADES:	return "Sigma Designs";
@@ -756,6 +759,7 @@
 	      case PCI_VENDOR_ID_SATSAGEM:	return "SatSagem";
 	      case PCI_VENDOR_ID_HUGHES:	return "Hughes";
 	      case PCI_VENDOR_ID_ENSONIQ:	return "Ensoniq";
+	      case PCI_VENDOR_ID_ALTEON:	return "Alteon";
 	      case PCI_VENDOR_ID_PICTUREL:	return "Picture Elements";
 	      case PCI_VENDOR_ID_NVIDIA_SGS:	return "NVidia/SGS Thomson";
 	      case PCI_VENDOR_ID_CBOARDS:	return "ComputerBoards";
diff -u --recursive --new-file v2.1.111/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- v2.1.111/linux/drivers/scsi/eata.c	Sun Jun  7 11:16:34 1998
+++ linux/drivers/scsi/eata.c	Sun Jul 26 12:56:08 1998
@@ -1,6 +1,21 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
+ *      26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111
+ *        + Added command line option (rs:[y|n]) to reverse the scan order
+ *          of PCI boards. The default is rs:y, which reverses the BIOS order
+ *          while registering PCI boards. The default value rs:y generates
+ *          the same order of all previous revisions of this driver.
+ *          Pls. note that "BIOS order" might have been reversed itself
+ *          after the 2.1.9x PCI modifications in the linux kernel.
+ *          The rs value is ignored when the explicit list of addresses
+ *          is used by the "eata=port0,port1,..." command line option.
+ *        + Added command line option (et:[y|n]) to force use of extended
+ *          translation (255 heads, 63 sectors) as disk geometry.
+ *          The default is et:n, which uses the disk geometry returned
+ *          by scsicam_bios_param. The default value et:n is compatible with
+ *          all previous revisions of this driver.
+ *
  *      28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104
  *          Increased busy timeout from 10 msec. to 200 msec. while
  *          processing interrupts.
@@ -193,6 +208,10 @@
  *  PM3222     -  SmartRAID Adapter for EISA (PM3222W is 16-bit wide SCSI)
  *  PM3224     -  SmartRAID Adapter for PCI  (PM3224W is 16-bit wide SCSI)
  *
+ *  The above list is just an indication: as a matter of fact all DPT
+ *  boards using the EATA/DMA protocol are supported by this driver,
+ *  since they use exactely the same programming interface.
+ *
  *  The DPT PM2001 provides only the EATA/PIO interface and hence is not
  *  supported by this driver.
  *
@@ -255,6 +274,10 @@
  *
  *  eh:y  use new scsi code (linux 2.2 only);
  *  eh:n  use old scsi code;
+ *  et:y  force use of extended translation (255 heads, 63 sectors);
+ *  et:n  use disk geometry detected by scsicam_bios_param;
+ *  rs:y  reverse scan order while detecting PCI boards;
+ *  rs:n  use BIOS order while detecting PCI boards;
  *  lc:y  enables linked commands;
  *  lc:n  disables linked commands;
  *  tc:y  enables tagged commands;
@@ -265,15 +288,16 @@
  *  tm:3  use only ordered queue tags;
  *  mq:xx set the max queue depth to the value xx (2 <= xx <= 32).
  *
- *  The default value is: "eata=lc:n,tc:n,mq:16,tm:0". An example using
- *  the list of detection probes could be:
- *  "eata=0x7410,0x230,lc:y,tc:n,mq:4,eh:n".
+ *  The default value is: "eata=lc:n,tc:n,mq:16,tm:0,et:n,rs:n".
+ *  An example using the list of detection probes could be:
+ *  "eata=0x7410,0x230,lc:y,tc:n,mq:4,eh:n,et:n".
  *
  *  When loading as a module, parameters can be specified as well.
  *  The above example would be (use 1 in place of y and 0 in place of n):
  *
  *  modprobe eata io_port=0x7410,0x230 linked_comm=1 tagged_comm=0 \
- *                max_queue_depth=4 tag_mode=0 use_new_eh_code=0
+ *                max_queue_depth=4 tag_mode=0 use_new_eh_code=0 \
+ *                ext_tran=0 rev_scan=1
  *
  *  ----------------------------------------------------------------------------
  *  In this implementation, linked commands are designed to work with any DISK
@@ -307,6 +331,19 @@
  *        When the driver detects a batch including overlapping requests
  *        (a really rare event) strict serial (pid) order is enforced.
  *  ----------------------------------------------------------------------------
+ *  The extended translation option (et:y) is useful when using large physical
+ *  disks/arrays. It could also be useful when switching between Adaptec boards
+ *  and DPT boards without reformatting the disk.
+ *  When a boot disk is partitioned with extended translation, in order to
+ *  be able to boot it with a DPT board is could be necessary to add to
+ *  lilo.conf additional commands as in the following example:
+ *
+ *  fix-table
+ *  disk=/dev/sda bios=0x80 sectors=63 heads=128 cylindres=546
+ *
+ *  where the above geometry should be replaced with the one reported at
+ *  power up by the DPT controller.
+ *  ----------------------------------------------------------------------------
  *
  *  The boards are named EATA0, EATA1,... according to the detection order.
  *
@@ -330,6 +367,8 @@
 MODULE_PARM(max_queue_depth, "i");
 MODULE_PARM(tag_mode, "i");
 MODULE_PARM(use_new_eh_code, "i");
+MODULE_PARM(ext_tran, "i");
+MODULE_PARM(rev_scan, "i");
 MODULE_AUTHOR("Dario Ballabio");
 #endif
 
@@ -413,6 +452,7 @@
 #undef  DEBUG_RESET
 #undef  DEBUG_GENERATE_ERRORS
 #undef  DEBUG_GENERATE_ABORTS
+#undef  DEBUG_GEOMETRY
 
 #define MAX_ISA 4
 #define MAX_VESA 0
@@ -663,6 +703,8 @@
 static int setup_done = FALSE;
 static int link_statistics = 0;
 static int tag_mode = TAG_MIXED;
+static int ext_tran = FALSE;
+static int rev_scan = TRUE;
 
 #if defined(CONFIG_SCSI_EATA_TAGGED_QUEUE)
 static int tagged_comm = TRUE;
@@ -1067,9 +1109,9 @@
 
    if (j == 0) {
       printk("EATA/DMA 2.0x: Copyright (C) 1994-1998 Dario Ballabio.\n");
-      printk("%s config options -> tc:%c, lc:%c, mq:%d, eh:%c.\n",
-             driver_name, tag_type, YESNO(linked_comm),
-             max_queue_depth, YESNO(use_new_eh_code));
+      printk("%s config options -> tc:%c, lc:%c, mq:%d, eh:%c, rs:%c, et:%c.\n",
+             driver_name, tag_type, YESNO(linked_comm), max_queue_depth,
+             YESNO(use_new_eh_code), YESNO(rev_scan), YESNO(ext_tran));
       }
 
    printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d.\n",
@@ -1132,6 +1174,8 @@
       else if (!strncmp(cur, "mq:", 3))  max_queue_depth = val;
       else if (!strncmp(cur, "ls:", 3))  link_statistics = val;
       else if (!strncmp(cur, "eh:", 3))  use_new_eh_code = val;
+      else if (!strncmp(cur, "et:", 3))  ext_tran = val;
+      else if (!strncmp(cur, "rs:", 3))  rev_scan = val;
 
       if ((cur = strchr(cur, ','))) ++cur;
       }
@@ -1165,8 +1209,8 @@
       if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
              continue;
 
-      /* Reverse the returned address order */
-      io_port[MAX_INT_PARAM + MAX_PCI - k] =
+      /* Order addresses according to rev_scan value */
+      io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] =
              (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
       }
 
@@ -1193,8 +1237,8 @@
       if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
              continue;
 
-      /* Reverse the returned address order */
-      io_port[MAX_INT_PARAM + MAX_PCI - k] =
+      /* Order addresses according to rev_scan value */
+      io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] =
              (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
       }
 
@@ -1845,6 +1889,23 @@
 }
 
 #endif /* new_eh_code */
+
+int eata2x_biosparam(Disk *disk, kdev_t dev, int *dkinfo) {
+   int size = disk->capacity;
+
+   if (ext_tran || (scsicam_bios_param(disk, dev, dkinfo) < 0)) {
+      dkinfo[0] = 255;
+      dkinfo[1] = 63;
+      dkinfo[2] = size / (dkinfo[0] * dkinfo[1]);
+      }
+
+#if defined (DEBUG_GEOMETRY)
+   printk ("%s: biosparam, head=%d, sec=%d, cyl=%d.\n", driver_name,
+           dkinfo[0], dkinfo[1], dkinfo[2]);
+#endif
+
+   return FALSE;
+}
 
 static void sort(unsigned long sk[], unsigned int da[], unsigned int n,
                  unsigned int rev) {
diff -u --recursive --new-file v2.1.111/linux/drivers/scsi/eata.h linux/drivers/scsi/eata.h
--- v2.1.111/linux/drivers/scsi/eata.h	Sun Jun  7 11:16:34 1998
+++ linux/drivers/scsi/eata.h	Tue Jul 28 13:52:09 1998
@@ -14,8 +14,9 @@
 int eata2x_old_abort(Scsi_Cmnd *);
 int eata2x_reset(Scsi_Cmnd *);
 int eata2x_old_reset(Scsi_Cmnd *, unsigned int);
+int eata2x_biosparam(Disk *, kdev_t, int *);
 
-#define EATA_VERSION "4.32.00"
+#define EATA_VERSION "4.33.00"
 
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 
@@ -32,7 +33,7 @@
                 eh_device_reset_handler: NULL,                               \
                 eh_bus_reset_handler:    NULL,                               \
                 eh_host_reset_handler:   eata2x_reset,                       \
-                bios_param:              scsicam_bios_param,                 \
+                bios_param:              eata2x_biosparam,                   \
                 this_id:                 7,                                  \
                 unchecked_isa_dma:       1,                                  \
                 use_clustering:          ENABLE_CLUSTERING,                  \
@@ -48,7 +49,7 @@
                 queuecommand:            eata2x_queuecommand,                \
                 abort:                   eata2x_old_abort,                   \
                 reset:                   eata2x_old_reset,                   \
-                bios_param:              scsicam_bios_param,                 \
+                bios_param:              eata2x_biosparam,                   \
                 this_id:                 7,                                  \
                 unchecked_isa_dma:       1,                                  \
                 use_clustering:          ENABLE_CLUSTERING                   \
diff -u --recursive --new-file v2.1.111/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- v2.1.111/linux/drivers/scsi/ide-scsi.c	Thu May 14 19:47:41 1998
+++ linux/drivers/scsi/ide-scsi.c	Sun Jul 26 11:46:46 1998
@@ -772,7 +772,7 @@
 	rq->cmd = IDESCSI_PC_RQ;
 	spin_unlock(&io_request_lock);
 	(void) ide_do_drive_cmd (drive, rq, ide_end);
-	spin_lock(&io_request_lock);
+	spin_lock_irq(&io_request_lock);
 	return 0;
 abort:
 	if (pc) kfree (pc);
diff -u --recursive --new-file v2.1.111/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.1.111/linux/drivers/scsi/scsi.c	Sun Jul 26 11:57:16 1998
+++ linux/drivers/scsi/scsi.c	Mon Jul 27 21:05:15 1998
@@ -274,6 +274,7 @@
 {"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"NRC","MBR-7.4","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"NAKAMICH","MJ-4.8S","*", BLIST_FORCELUN | BLIST_SINGLELUN},
+{"NAKAMICH","MJ-5.16S","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"PIONEER","CD-ROM DRM-600","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"PIONEER","CD-ROM DRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
@@ -750,6 +751,7 @@
   case TYPE_MOD:
   case TYPE_PROCESSOR:
   case TYPE_SCANNER:
+  case TYPE_MEDIUM_CHANGER:
     SDpnt->writeable = 1;
     break;
   case TYPE_WORM:
diff -u --recursive --new-file v2.1.111/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c
--- v2.1.111/linux/drivers/scsi/scsi_error.c	Wed May 20 19:10:40 1998
+++ linux/drivers/scsi/scsi_error.c	Mon Jul 27 18:21:59 1998
@@ -21,7 +21,7 @@
 #include <linux/blk.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <asm/smp_lock.h>
+#include <linux/smp_lock.h>
 
 #define __KERNEL_SYSCALLS__
 
diff -u --recursive --new-file v2.1.111/linux/drivers/scsi/scsi_queue.c linux/drivers/scsi/scsi_queue.c
--- v2.1.111/linux/drivers/scsi/scsi_queue.c	Sun Jun  7 11:16:35 1998
+++ linux/drivers/scsi/scsi_queue.c	Mon Jul 27 18:22:12 1998
@@ -23,7 +23,7 @@
 #include <linux/blk.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <asm/smp_lock.h>
+#include <linux/smp_lock.h>
 
 #define __KERNEL_SYSCALLS__
 
diff -u --recursive --new-file v2.1.111/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.1.111/linux/drivers/scsi/sd.c	Thu May  7 22:51:51 1998
+++ linux/drivers/scsi/sd.c	Mon Jul 27 18:21:42 1998
@@ -37,7 +37,6 @@
 #include <linux/interrupt.h>
 
 #include <linux/smp.h>
-#include <asm/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
diff -u --recursive --new-file v2.1.111/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
--- v2.1.111/linux/drivers/scsi/u14-34f.c	Sun Jun  7 11:16:35 1998
+++ linux/drivers/scsi/u14-34f.c	Sun Jul 26 12:56:08 1998
@@ -1,6 +1,14 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *      26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111
+ *          Added command line option (et:[y|n]) to use the existing
+ *          translation (returned by scsicam_bios_param) as disk geometry.
+ *          The default is et:n, which uses the disk geometry jumpered
+ *          on the board.
+ *          The default value et:n is compatible with all previous revisions
+ *          of this driver.
+ *
  *      28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104
  *          Increased busy timeout from 10 msec. to 200 msec. while
  *          processing interrupts.
@@ -245,20 +253,23 @@
  *
  *  eh:y  use new scsi code (linux 2.2 only);
  *  eh:n  use old scsi code;
+ *  et:y  use disk geometry returned by scsicam_bios_param;
+ *  et:n  use disk geometry jumpered on the board;
  *  lc:y  enables linked commands;
  *  lc:n  disables linked commands;
  *  of:y  enables old firmware support;
  *  of:n  disables old firmware support;
  *  mq:xx set the max queue depth to the value xx (2 <= xx <= 8).
  *
- *  The default value is: "u14-34f=lc:n,of:n,mq:8". An example using the list
- *  of detection probes could be: "u14-34f=0x230,0x340,lc:y,of:n,mq:4,eh:n".
+ *  The default value is: "u14-34f=lc:n,of:n,mq:8,et:n".
+ *  An example using the list of detection probes could be:
+ *  "u14-34f=0x230,0x340,lc:y,of:n,mq:4,eh:n,et:n".
  *
  *  When loading as a module, parameters can be specified as well.
  *  The above example would be (use 1 in place of y and 0 in place of n):
  *
  *  modprobe u14-34f io_port=0x230,0x340 linked_comm=1 have_old_firmware=0 \
- *                max_queue_depth=4 use_new_eh_code=0
+ *                max_queue_depth=4 use_new_eh_code=0 ext_tran=0
  *
  *  ----------------------------------------------------------------------------
  *  In this implementation, linked commands are designed to work with any DISK
@@ -314,6 +325,7 @@
 MODULE_PARM(link_statistics, "i");
 MODULE_PARM(max_queue_depth, "i");
 MODULE_PARM(use_new_eh_code, "i");
+MODULE_PARM(ext_tran, "i");
 MODULE_AUTHOR("Dario Ballabio");
 #endif
 
@@ -405,6 +417,7 @@
 #undef  DEBUG_RESET
 #undef  DEBUG_GENERATE_ERRORS
 #undef  DEBUG_GENERATE_ABORTS
+#undef  DEBUG_GEOMETRY
 
 #define MAX_ISA 3
 #define MAX_VESA 1
@@ -556,6 +569,7 @@
 static int do_trace = FALSE;
 static int setup_done = FALSE;
 static int link_statistics = 0;
+static int ext_tran = FALSE;
 
 #if defined(HAVE_OLD_UX4F_FIRMWARE)
 static int have_old_firmware = TRUE;
@@ -876,9 +890,9 @@
 
    if (j == 0) {
       printk("UltraStor 14F/34F: Copyright (C) 1994-1998 Dario Ballabio.\n");
-      printk("%s config options -> of:%c, lc:%c, mq:%d, eh:%c.\n",
+      printk("%s config options -> of:%c, lc:%c, mq:%d, eh:%c, et:%c.\n",
              driver_name, YESNO(have_old_firmware), YESNO(linked_comm),
-             max_queue_depth, YESNO(use_new_eh_code));
+             max_queue_depth, YESNO(use_new_eh_code), YESNO(ext_tran));
       }
 
    printk("%s: %s 0x%03lx, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d.\n",
@@ -922,6 +936,7 @@
       else if (!strncmp(cur, "mq:", 3))  max_queue_depth = val;
       else if (!strncmp(cur, "ls:", 3))  link_statistics = val;
       else if (!strncmp(cur, "eh:", 3))  use_new_eh_code = val;
+      else if (!strncmp(cur, "et:", 3))  ext_tran = val;
 
       if ((cur = strchr(cur, ','))) ++cur;
       }
@@ -1555,6 +1570,18 @@
    dkinfo[0] = HD(j)->heads;
    dkinfo[1] = HD(j)->sectors;
    dkinfo[2] = size / (HD(j)->heads * HD(j)->sectors);
+
+   if (ext_tran && (scsicam_bios_param(disk, dev, dkinfo) < 0)) {
+      dkinfo[0] = 255;
+      dkinfo[1] = 63;
+      dkinfo[2] = size / (dkinfo[0] * dkinfo[1]);
+      }
+
+#if defined (DEBUG_GEOMETRY)
+   printk ("%s: biosparam, head=%d, sec=%d, cyl=%d.\n", driver_name,
+           dkinfo[0], dkinfo[1], dkinfo[2]);
+#endif
+
    return FALSE;
 }
 
diff -u --recursive --new-file v2.1.111/linux/drivers/scsi/u14-34f.h linux/drivers/scsi/u14-34f.h
--- v2.1.111/linux/drivers/scsi/u14-34f.h	Sun Jun  7 11:16:35 1998
+++ linux/drivers/scsi/u14-34f.h	Tue Jul 28 13:52:09 1998
@@ -4,6 +4,7 @@
 #ifndef _U14_34F_H
 #define _U14_34F_H
 
+#include <scsi/scsicam.h>
 #include <linux/version.h>
 
 int u14_34f_detect(Scsi_Host_Template *);
@@ -15,7 +16,7 @@
 int u14_34f_old_reset(Scsi_Cmnd *, unsigned int);
 int u14_34f_biosparam(Disk *, kdev_t, int *);
 
-#define U14_34F_VERSION "4.32.00"
+#define U14_34F_VERSION "4.33.00"
 
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 
diff -u --recursive --new-file v2.1.111/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c
--- v2.1.111/linux/drivers/sgi/char/shmiq.c	Tue Mar 10 10:03:33 1998
+++ linux/drivers/sgi/char/shmiq.c	Mon Jul 27 18:22:28 1998
@@ -50,8 +50,8 @@
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
 #include <linux/major.h>
+#include <linux/smp_lock.h>
 
-#include <asm/smp_lock.h>
 #include <asm/shmiq.h>
 #include <asm/mman.h>
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.1.111/linux/drivers/sgi/char/usema.c linux/drivers/sgi/char/usema.c
--- v2.1.111/linux/drivers/sgi/char/usema.c	Wed Dec 10 10:31:11 1997
+++ linux/drivers/sgi/char/usema.c	Mon Jul 27 18:22:42 1998
@@ -31,8 +31,8 @@
 #include <linux/dcache.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 
-#include <asm/smp_lock.h>
 #include <asm/usioctl.h>
 #include <asm/mman.h>
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.1.111/linux/drivers/sound/msnd.c linux/drivers/sound/msnd.c
--- v2.1.111/linux/drivers/sound/msnd.c	Sun Jul 26 11:57:16 1998
+++ linux/drivers/sound/msnd.c	Sat Jul 25 18:48:29 1998
@@ -24,7 +24,6 @@
  *
  ********************************************************************/
 
-#include <linux/config.h>
 #include <linux/version.h>
 #if LINUX_VERSION_CODE < 0x020101
 #  define LINUX20
diff -u --recursive --new-file v2.1.111/linux/drivers/sound/msnd_classic.h linux/drivers/sound/msnd_classic.h
--- v2.1.111/linux/drivers/sound/msnd_classic.h	Sun Jul 26 11:57:16 1998
+++ linux/drivers/sound/msnd_classic.h	Sat Jul 25 18:48:29 1998
@@ -30,6 +30,8 @@
 #ifndef __MSND_CLASSIC_H
 #define __MSND_CLASSIC_H
 
+#include <linux/config.h>
+
 #define DSP_NUMIO		0x10
 
 #define	HP_MEMM			0x08
diff -u --recursive --new-file v2.1.111/linux/drivers/sound/msnd_pinnacle.h linux/drivers/sound/msnd_pinnacle.h
--- v2.1.111/linux/drivers/sound/msnd_pinnacle.h	Sun Jul 26 11:57:16 1998
+++ linux/drivers/sound/msnd_pinnacle.h	Sat Jul 25 18:48:29 1998
@@ -30,6 +30,8 @@
 #ifndef __MSND_PINNACLE_H
 #define __MSND_PINNACLE_H
 
+#include <linux/config.h>
+
 #define DSP_NUMIO		0x08
 
 #define	HP_DSPR			0x04
diff -u --recursive --new-file v2.1.111/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- v2.1.111/linux/drivers/video/Config.in	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/Config.in	Sun Jul 26 14:40:19 1998
@@ -23,6 +23,7 @@
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       bool 'Amiga CyberVision3D support (experimental)' CONFIG_FB_VIRGE
       tristate 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3
+      tristate 'Amiga CLgen driver' CONFIG_FB_CLGEN
     fi
   fi
   if [ "$CONFIG_ATARI" = "y" ]; then
@@ -32,8 +33,8 @@
   if [ "$CONFIG_PPC" = "y" ]; then
     bool 'Open Firmware frame buffer device support' CONFIG_FB_OF
     if [ "$CONFIG_FB_OF" = "y" ]; then
-#     bool 'Apple "control" display support' CONFIG_FB_CONTROL
-#     bool 'Apple "platinum" display support' CONFIG_FB_PLATINUM
+      bool 'Apple "control" display support' CONFIG_FB_CONTROL
+      bool 'Apple "platinum" display support' CONFIG_FB_PLATINUM
 #     bool 'Apple "valkyrie" display support' CONFIG_FB_VALKYRIE
       bool 'ATI Mach64 display support' CONFIG_FB_ATY
 #     bool 'IMS Twin Turbo display support' CONFIG_FB_IMSTT
@@ -69,7 +70,12 @@
       if [ "$ARCH" = "sparc64" ]; then
 	bool '  Creator/Creator3D support' CONFIG_FB_CREATOR
       fi
-      bool '  CGsix (GX,GXplus) support' CONFIG_FB_CGSIX
+      bool '  CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
+      bool '  BWtwo support' CONFIG_FB_BWTWO
+      bool '  CGthree support' CONFIG_FB_CGTHREE
+      if [ "$ARCH" = "sparc" ]; then
+        bool '  TCX (SS4/SS5 only) support' CONFIG_FB_TCX
+      fi
     fi
   fi
   if [ "$ARCH" = "sparc64" ]; then
@@ -104,13 +110,15 @@
     if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_AMIGA" = "y" -o \
 	 "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
 	 "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \
-	 "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
+	 "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+	 "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then
       define_bool CONFIG_FBCON_MFB y
     else
       if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \
 	   "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
 	   "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_RETINAZ3" = "m" -o \
-	   "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+	   "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	   "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then
 	define_bool CONFIG_FBCON_MFB m
       fi
     fi
@@ -128,40 +136,50 @@
     if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_ATARI" = "y" -o \
 	 "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
 	 "$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_TGA" = "y" -o \
-	 "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
+	 "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+	 "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \
+	 "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then
       define_bool CONFIG_FBCON_CFB8 y
     else
       if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
 	   "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
 	   "$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \
-	   "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+	   "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	   "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \
+	   "$CONFIG_FB_CONTROL" = "m" ]; then
 	define_bool CONFIG_FBCON_CFB8 m
       fi
     fi
     if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
 	 "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
-	 "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" ]; then
+	 "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \
+	 "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "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" ]; then
+	   "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \
+	   "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then
 	define_bool CONFIG_FBCON_CFB16 m
       fi
     fi
-    if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
+    if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+	 "$CONFIG_FB_CLGEN" = "y" ]; then
       define_bool CONFIG_FBCON_CFB24 y
     else
-      if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+      if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	   "$CONFIG_FB_CLGEN" = "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" ]; then
+	 "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+	 "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "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" ]; then
+	   "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+	   "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then
 	define_bool CONFIG_FBCON_CFB32 m
       fi
     fi
@@ -202,14 +220,19 @@
       fi
     fi
   fi
+  bool 'Support only 8 pixels wide fonts' CONFIG_FBCON_FONTWIDTH8_ONLY
   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
     bool 'Sparc console 8x16 font' CONFIG_FONT_SUN8x16
-    bool 'Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
+    if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+      bool 'Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
+    fi
     bool 'Select other fonts' CONFIG_FBCON_FONTS
     if [ "$CONFIG_FBCON_FONTS" = "y" ]; then
       bool '  VGA 8x8 font' CONFIG_FONT_8x8
       bool '  VGA 8x16 font' CONFIG_FONT_8x16
-      bool '  Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+      if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+        bool '  Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+      fi
       bool '  Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8
       bool '  Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8
     fi
@@ -219,15 +242,19 @@
       bool '  VGA 8x8 font' CONFIG_FONT_8x8
       bool '  VGA 8x16 font' CONFIG_FONT_8x16
       bool '  Sparc console 8x16 font' CONFIG_FONT_SUN8x16
-      bool '  Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
-      bool '  Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+      if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+        bool '  Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
+        bool '  Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+      fi
       bool '  Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8
       bool '  Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8
     else
       define_bool CONFIG_FONT_8x8 y
       define_bool CONFIG_FONT_8x16 y
       if [ "$CONFIG_MAC" = "y" ]; then
-        define_bool CONFIG_FONT_6x11 y
+	if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+          define_bool CONFIG_FONT_6x11 y
+        fi
       fi
       if [ "$CONFIG_AMIGA" = "y" ]; then
         define_bool CONFIG_FONT_PEARL_8x8 y
diff -u --recursive --new-file v2.1.111/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.1.111/linux/drivers/video/Makefile	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/Makefile	Sun Jul 26 14:40:19 1998
@@ -30,13 +30,13 @@
 endif
 
 ifeq ($(CONFIG_PROM_CONSOLE),y)
-  L_OBJS += promcon.o
+  L_OBJS += promcon.o promcon_tbl.o
 endif
 
 ifeq ($(CONFIG_FB),y)
   L_OBJS += fonts.o
   OX_OBJS += fbcon.o fbcmap.o
-# fbgen is not compiled by default since nobody uses it yet
+# fbgen is not compiled by default since nobody uses it yet, except clgenfb
   ifeq ($(CONFIG_FONT_8x8),y)
     L_OBJS += font_8x8.o
   endif
@@ -94,6 +94,14 @@
 L_OBJS += atyfb.o
 endif
 
+ifeq ($(CONFIG_FB_CONTROL),y)
+L_OBJS += controlfb.o
+endif
+
+ifeq ($(CONFIG_FB_PLATINUM),y)
+L_OBJS += platinumfb.o
+endif
+
 ifeq ($(CONFIG_FB_CT65550),y)
 L_OBJS += chipsfb.o
 endif
@@ -126,6 +134,16 @@
   endif
 endif
 
+ifeq ($(CONFIG_FB_CLGEN),y)
+L_OBJS += clgenfb.o
+OX_OBJS += fbgen.o
+else
+  ifeq ($(CONFIG_FB_CLGEN),m)
+  M_OBJS += clgenfb.o
+  OX_OBJS += fbgen.o
+  endif
+endif
+
 ifeq ($(CONFIG_FB_S3TRIO),y)
 L_OBJS += S3triofb.o
 else
@@ -186,6 +204,27 @@
     M_OBJS += cgsixfb.o
     endif
   endif
+  ifeq ($(CONFIG_FB_BWTWO),y)
+    L_OBJS += bwtwofb.o
+  else
+    ifeq ($(CONFIG_FB_BWTWO),m)
+    M_OBJS += bwtwofb.o
+    endif
+  endif
+  ifeq ($(CONFIG_FB_CGTHREE),y)
+    L_OBJS += cgthreefb.o
+  else
+    ifeq ($(CONFIG_FB_CGTHREE),m)
+    M_OBJS += cgthreefb.o
+    endif
+  endif
+  ifeq ($(CONFIG_FB_TCX),y)
+    L_OBJS += tcxfb.o
+  else
+    ifeq ($(CONFIG_FB_TCX),m)
+    M_OBJS += tcxfb.o
+    endif
+  endif
 else
   ifeq ($(CONFIG_FB_SBUS),m)
   M_OBJS += sbusfb.o
@@ -203,6 +242,27 @@
       M_OBJS += cgsixfb.o
       endif
     endif
+    ifeq ($(CONFIG_FB_BWTWO),y)
+      M_OBJS += bwtwofb.o
+    else
+      ifeq ($(CONFIG_FB_BWTWO),m)
+      M_OBJS += bwtwofb.o
+      endif
+    endif
+    ifeq ($(CONFIG_FB_CGTHREE),y)
+      M_OBJS += cgthreefb.o
+    else
+      ifeq ($(CONFIG_FB_CGTHREE),m)
+      M_OBJS += cgthreefb.o
+      endif
+    endif
+    ifeq ($(CONFIG_FB_TCX),y)
+      M_OBJS += tcxfb.o
+    else
+      ifeq ($(CONFIG_FB_TCX),m)
+      M_OBJS += tcxfb.o
+      endif
+    endif
   endif
 endif
 
@@ -353,3 +413,10 @@
 gspcore.c: gspcore.gsp
 	$(GSPA) $< > $*.hex
 	$(GSPH2C) $*.hex > gspcore.c
+
+promcon_tbl.c: prom.uni
+	../char/conmakehash prom.uni | \
+	sed -e '/#include <[^>]*>/p' -e 's/types/init/' \
+	    -e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > promcon_tbl.c
+
+promcon_tbl.o: promcon_tbl.c $(TOPDIR)/include/linux/types.h
diff -u --recursive --new-file v2.1.111/linux/drivers/video/atafb.c linux/drivers/video/atafb.c
--- v2.1.111/linux/drivers/video/atafb.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/atafb.c	Sun Jul 26 14:40:19 1998
@@ -47,6 +47,7 @@
 #define ATAFB_EXT
 #define ATAFB_FALCON
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.1.111/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
--- v2.1.111/linux/drivers/video/atyfb.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/atyfb.c	Sun Jul 26 14:40:19 1998
@@ -1,7 +1,7 @@
 /*
  *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
  *
- *	Copyright (C) 1997 Geert Uytterhoeven
+ *	Copyright (C) 1997-1998 Geert Uytterhoeven
  *	Copyright (C) 1998 Bernd Harries
  *	Copyright (C) 1998 Eddie C. Dost
  *
@@ -26,26 +26,19 @@
 
   TODO:
 
-    - support arbitrary video modes
-
   (ecd):
 
-    - fix initialization and allocation of resources for cursor (and disp?).
-
     - fix initialization of cursor timer.
 
-    - add code to detect ramdac type on initialization.
-
     - add code to support cursor on all cards and all ramdacs.
 
     - make cursor parameters controllable via ioctl()s.
 
-    - handle arbitrary fonts.
-
 						(Anyone to help with all this?)
 
 ******************************************************************************/
 
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -63,10 +56,15 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/nvram.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+
 #ifdef CONFIG_FB_COMPAT_XPMAC
 #include <asm/vc_ioctl.h>
 #endif
+
 #include <asm/io.h>
+
 #if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
@@ -80,157 +78,76 @@
 #include "fbcon.h"
 #include "fbcon-cfb8.h"
 #include "fbcon-cfb16.h"
+#include "fbcon-cfb24.h"
 #include "fbcon-cfb32.h"
 
 
-#ifndef __powerpc__
-#define eieio()		/* Enforce In-order Execution of I/O */
-#endif
-
-static int currcon = 0;
-static struct display fb_disp;
-
-static char atyfb_name[16] = "ATY Mach64";
-
-struct atyfb_par {
-    union {
-	/* this should contain chipset specific mode information */
-	struct {
-	    int vmode;
-	    int cmode;
-	} gx, gt, vt;
-    } hw;
-    u_int vxres;	/* virtual screen size */
-    u_int vyres;
-    int xoffset;	/* virtual screen position */
-    int yoffset;
-    int accel;
-};
-
+#define GUI_RESERVE	0x00001000
 
-/*
- * Video mode values.
- * These are supposed to be the same as the values that
- * Apple uses in MacOS.
- */
-#define VMODE_NVRAM		0	/* use value stored in nvram */
-#define VMODE_512_384_60I	1	/* 512x384, 60Hz interlaced (NTSC) */
-#define VMODE_512_384_60	2	/* 512x384, 60Hz */
-#define VMODE_640_480_50I	3	/* 640x480, 50Hz interlaced (PAL) */
-#define VMODE_640_480_60I	4	/* 640x480, 60Hz interlaced (NTSC) */
-#define VMODE_640_480_60	5	/* 640x480, 60Hz (VGA) */
-#define VMODE_640_480_67	6	/* 640x480, 67Hz */
-#define VMODE_640_870_75P	7	/* 640x870, 75Hz (portrait) */
-#define VMODE_768_576_50I	8	/* 768x576, 50Hz (PAL full frame) */
-#define VMODE_800_600_56	9	/* 800x600, 56Hz */
-#define VMODE_800_600_60	10	/* 800x600, 60Hz */
-#define VMODE_800_600_72	11	/* 800x600, 72Hz */
-#define VMODE_800_600_75	12	/* 800x600, 75Hz */
-#define VMODE_832_624_75	13	/* 832x624, 75Hz */
-#define VMODE_1024_768_60	14	/* 1024x768, 60Hz */
-#define VMODE_1024_768_70	15	/* 1024x768, 70Hz (or 72Hz?) */
-#define VMODE_1024_768_75V	16	/* 1024x768, 75Hz (VESA) */
-#define VMODE_1024_768_75	17	/* 1024x768, 75Hz */
-#define VMODE_1152_870_75	18	/* 1152x870, 75Hz */
-#define VMODE_1280_960_75	19	/* 1280x960, 75Hz */
-#define VMODE_1280_1024_75	20	/* 1280x1024, 75Hz */
-#define VMODE_MAX		20
-#define VMODE_CHOOSE		99	/* choose based on monitor sense */
+#define CLASS_GX	1
+#define CLASS_CT	2
+#define CLASS_VT	3
+#define CLASS_GT	4
 
-/*
- * Color mode values, used to select number of bits/pixel.
- */
-#define CMODE_NVRAM		-1	/* use value stored in nvram */
-#define CMODE_8			0	/* 8 bits/pixel */
-#define CMODE_16		1	/* 16 (actually 15) bits/pixel */
-#define CMODE_32		2	/* 32 (actually 24) bits/pixel */
 
+#ifndef __powerpc__
+#define eieio()		/* Enforce In-order Execution of I/O */
+#endif
 
-static int default_vmode = VMODE_NVRAM;
-static int default_cmode = CMODE_NVRAM;
+/* FIXME: remove the FAIL definition */
+#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
 
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
-/*
- * Addresses in NVRAM where video mode and pixel size are stored.
- */
-#define NV_VMODE	0x140f
-#define NV_CMODE	0x1410
-#endif /* CONFIG_PMAC || CONFIG_CHRP */
 
+    /*
+     *  Elements of the Hardware specific atyfb_par structure
+     */
 
-/*
- * Horizontal and vertical resolution for each mode.
- */
-static struct vmode_attr {
-	int	hres;
-	int	vres;
-	int	vfreq;
-	int	interlaced;
-} vmode_attrs[VMODE_MAX] = {
-    {512, 384, 60, 1},
-    {512, 384, 60},
-    {640, 480, 50, 1},
-    {640, 480, 60, 1},
-    {640, 480, 60},
-    {640, 480, 67},
-    {640, 870, 75},
-    {768, 576, 50, 1},
-    {800, 600, 56},
-    {800, 600, 60},
-    {800, 600, 72},
-    {800, 600, 75},
-    {832, 624, 75},
-    {1024, 768, 60},
-    {1024, 768, 72},
-    {1024, 768, 75},
-    {1024, 768, 75},
-    {1152, 870, 75},
-    {1280, 960, 75},
-    {1280, 1024, 75}
+struct crtc {
+    u32 vxres;
+    u32 vyres;
+    u32 xoffset;
+    u32 yoffset;
+    u32 bpp;
+    u32 h_tot_disp;
+    u32 h_sync_strt_wid;
+    u32 v_tot_disp;
+    u32 v_sync_strt_wid;
+    u32 off_pitch;
+    u32 gen_cntl;
+    u32 dp_pix_width;	/* acceleration */
+    u32 dp_chain_mask;	/* acceleration */
 };
 
+struct pll_gx {
+    u8 m;
+    u8 n;
+};
 
-/*
- * We get a sense value from the monitor and use it to choose
- * what resolution to use.  This structure maps sense values
- * to display mode values (which determine the resolution and
- * frequencies).
- */
-static struct mon_map {
-	int	sense;
-	int	vmode;
-} monitor_map [] = {
-	{0x000, VMODE_1280_1024_75},	/* 21" RGB */
-	{0x114, VMODE_640_870_75P},	/* Portrait Monochrome */
-	{0x221, VMODE_512_384_60},	/* 12" RGB*/
-	{0x331, VMODE_1280_1024_75},	/* 21" RGB (Radius) */
-	{0x334, VMODE_1280_1024_75},	/* 21" mono (Radius) */
-	{0x335, VMODE_1280_1024_75},	/* 21" mono */
-	{0x40A, VMODE_640_480_60I},	/* NTSC */
-	{0x51E, VMODE_640_870_75P},	/* Portrait RGB */
-	{0x603, VMODE_832_624_75},	/* 12"-16" multiscan */
-	{0x60b, VMODE_1024_768_70},	/* 13"-19" multiscan */
-	{0x623, VMODE_1152_870_75},	/* 13"-21" multiscan */
-	{0x62b, VMODE_640_480_67},	/* 13"/14" RGB */
-	{0x700, VMODE_640_480_50I},	/* PAL */
-	{0x714, VMODE_640_480_60I},	/* NTSC */
-	{0x717, VMODE_800_600_75},	/* VGA */
-	{0x72d, VMODE_832_624_75},	/* 16" RGB (Goldfish) */
-	{0x730, VMODE_768_576_50I},	/* PAL (Alternate) */
-	{0x73a, VMODE_1152_870_75},	/* 3rd party 19" */
-	{0x73f, VMODE_640_480_67},	/* no sense lines connected at all */
-	{-1,	VMODE_640_480_60},	/* catch-all, must be last */
+struct pll_ct {
+    u8 pll_ref_div;
+    u8 pll_gen_cntl;
+    u8 mclk_fb_div;
+    u8 pll_vclk_cntl;
+    u8 vclk_post_div;
+    u8 vclk_fb_div;
+    u8 pll_ext_cntl;
+    u32 dsp_config;	/* Mach64 GTB DSP */
+    u32 dsp_on_off;	/* Mach64 GTB DSP */
 };
 
-static int map_monitor_sense(int sense)
-{
-	struct mon_map *map;
 
-	for (map = monitor_map; map->sense >= 0; ++map)
-		if (map->sense == sense)
-			break;
-	return map->vmode;
-}
+    /*
+     *  The Hardware parameters for each card
+     */
+
+struct atyfb_par {
+    struct crtc crtc;
+    union {
+	struct pll_gx gx;
+	struct pll_ct ct;
+    } pll;
+    u32 accel_flags;
+};
 
 struct aty_cmap_regs {
     u8 windex;
@@ -240,27 +157,6 @@
     u8 cntl;
 };
 
-typedef struct aty_regvals {
-    u32 offset[3];		/* first pixel address */
-
-    u32 crtc_h_sync_strt_wid[3];	/* depth dependent */
-    u32 crtc_gen_cntl[3];
-    u32 mem_cntl[3];
-
-    u32 crtc_h_tot_disp;	/* mode dependent */
-    u32 crtc_v_tot_disp;
-    u32 crtc_v_sync_strt_wid;
-    u32 crtc_off_pitch;
-
-    u8 clock_val[2];	/* vals for 20 and 21 */
-} aty_regvals;
-
-struct rage_regvals {
-    u32 h_total, h_sync_start, h_sync_width;
-    u32 v_total, v_sync_start, v_sync_width;
-    u32 h_sync_neg, v_sync_neg;
-};
-
 struct pci_mmap_map {
     unsigned long voff;
     unsigned long poff;
@@ -272,18 +168,18 @@
 #define DEFAULT_CURSOR_BLINK_RATE	(20)
 
 struct aty_cursor {
-	int		   enable;
-    	int		   on;
-	int		   vbl_cnt;
-	int		   blink_rate;
-	u32		   offset;
-	struct {
-	    u16 x, y;
-	}		   pos, hot, size;
-	u32		   color[2];
-	u8		   bits[8][64];
-	u8		   mask[8][64];
-	struct timer_list *timer;
+    int	enable;
+    int on;
+    int vbl_cnt;
+    int blink_rate;
+    u32 offset;
+    struct {
+        u16 x, y;
+    } pos, hot, size;
+    u32 color[2];
+    u8 bits[8][64];
+    u8 mask[8][64];
+    struct timer_list *timer;
 };
 
 struct fb_info_aty {
@@ -292,144 +188,49 @@
     unsigned long ati_regbase;
     unsigned long frame_buffer_phys;
     unsigned long frame_buffer;
+    struct display disp;
+    struct display_switch dispsw;
     struct pci_mmap_map *mmap_map;
     struct aty_cursor *cursor;
-    u8 chip_class;
-    u8 pixclock_lim_8;	/* ps, <= 8 bpp */
-    u8 pixclock_lim_hi;	/* ps, > 8 bpp */
-    u32 total_vram;
     struct aty_cmap_regs *aty_cmap_regs;
     struct { u8 red, green, blue, pad; } palette[256];
     struct atyfb_par default_par;
     struct atyfb_par current_par;
-};
-
-#ifdef CONFIG_ATARI
-static unsigned int mach64_count __initdata = 0;
-static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, };
-static unsigned long phys_size[FB_MAX] __initdata = { 0, };
-static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
-#endif
-
-static int aty_vram_reqd(const struct atyfb_par *par);
-static struct aty_regvals *get_aty_struct(int vmode, struct fb_info_aty *info);
-
-#include "ati-gx.h"
-#include "ati-gt.h"
-#include "ati-vt.h"
-
-static struct aty_regvals *aty_gt_reg_init[20] = {
-	NULL, NULL, NULL, NULL,
-	&aty_gt_reg_init_5,
-	&aty_gt_reg_init_6,
-	NULL, NULL,
-	&aty_gt_reg_init_9,
-	&aty_gt_reg_init_10,
-	&aty_gt_reg_init_11,
-	&aty_gt_reg_init_12,
-	&aty_gt_reg_init_13,
-	&aty_gt_reg_init_14,
-	&aty_gt_reg_init_15,
-	NULL,
-	&aty_gt_reg_init_17,
-	&aty_gt_reg_init_18,
-	NULL,
-	&aty_gt_reg_init_20
-};
-
-static struct aty_regvals *aty_gx_reg_init[20] = {
-	NULL, NULL, NULL, NULL,
-	&aty_gx_reg_init_6,
-	&aty_gx_reg_init_6,
-	NULL, NULL, NULL, NULL, NULL, NULL,
-	&aty_gx_reg_init_13,
-	&aty_gx_reg_init_14,
-	&aty_gx_reg_init_15,
-	NULL,
-	&aty_gx_reg_init_17,
-	&aty_gx_reg_init_18,
-	NULL,
-	&aty_gx_reg_init_20
-};
-
-static struct aty_regvals *aty_vt_reg_init[21] = {
-	NULL, NULL, NULL, NULL,
-	&aty_vt_reg_init_5,
-	&aty_vt_reg_init_6,
-	NULL, NULL, NULL,
-	&aty_vt_reg_init_10,
-	&aty_vt_reg_init_11,
-	&aty_vt_reg_init_12,
-	&aty_vt_reg_init_13,
-	&aty_vt_reg_init_14,
-	&aty_vt_reg_init_15,
-	NULL,
-	&aty_vt_reg_init_17,
-	&aty_vt_reg_init_18,
-	&aty_vt_reg_init_19,
-	&aty_vt_reg_init_20
-};
-
-
-#define CLASS_GX	1
-#define CLASS_CT	2
-#define CLASS_VT	3
-#define CLASS_GT	4
-
-struct aty_features {
-    u16 pci_id;
+    u32 total_vram;
+    u32 pll_per;
+    u32 mclk_per;
     u16 chip_type;
-    const char *name;
-    u8 chip_class;
-    u8 pixclock_lim_8;	/* MHz, <= 8 bpp (not sure about these limits!) */
-    u8 pixclock_lim_hi;	/* MHz, > 8 bpp (not sure about these limits!) */
-} aty_features[] __initdata = {
-    /* mach64GX family */
-    { 0x4758, 0x00d7, "mach64GX (ATI888GX00)", CLASS_GX, 135, 80 },
-    { 0x4358, 0x0057, "mach64CX (ATI888CX00)", CLASS_GX, 135, 80 },
-
-    /* mach64CT family */
-    { 0x4354, 0x4354, "mach64CT (ATI264CT)", CLASS_CT, 135, 80 },
-    { 0x4554, 0x4554, "mach64ET (ATI264ET)", CLASS_CT, 135, 80 },
-
-    /* mach64CT family / mach64VT class */
-    { 0x5654, 0x5654, "mach64VT (ATI264VT)", CLASS_VT, 160, 135 },
-    { 0x5655, 0x5655, "mach64VTB (ATI264VTB)", CLASS_VT, 160, 135 },
-    { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)", CLASS_VT, 160, 135 },
-
-    /* mach64CT family / mach64GT (3D RAGE) class */
-    { 0x4742, 0x4742, "3D RAGE PRO (BGA, AGP)", CLASS_GT, 240, 240 },
-    { 0x4744, 0x4744, "3D RAGE PRO (BGA, AGP, 1x only)", CLASS_GT, 240, 240 },
-    { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)", CLASS_GT, 240, 240 },
-    { 0x4750, 0x4750, "3D RAGE PRO (PQFP, PCI)", CLASS_GT, 240, 240 },
-    { 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)", CLASS_GT, 240, 240 },
-    { 0x4754, 0x4754, "3D RAGE (GT)", CLASS_GT, 200, 200 },
-    { 0x4755, 0x4755, "3D RAGE II+ (GTB)", CLASS_GT, 200, 200 },
-    { 0x4756, 0x4756, "3D RAGE IIC", CLASS_GT, 200, 200 },
-    { 0x4c47, 0x4c47, "3D RAGE LT", CLASS_GT, 200, 200 },
+#define Gx info->chip_type
+    u8 chip_rev;
+#define Rev info->chip_rev
+    u8 bus_type;
+    u8 ram_type;
+    u8 dac_type;
+    u8 clk_type;
+    u8 mem_refresh_rate;
+#ifdef __sparc__
+    u8 open;
+    u8 mmaped;
+    int vtconsole;
+    int consolecnt;
+#endif
 };
 
 
     /*
-     *  Interface used by the world
+     *  Frame buffer device API
      */
 
-void atyfb_init(void);
-#ifdef CONFIG_FB_OF
-void atyfb_of_init(struct device_node *dp);
-#endif
-void atyfb_setup(char *options, int *ints);
-
 static int atyfb_open(struct fb_info *info, int user);
 static int atyfb_release(struct fb_info *info, int user);
 static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info);
+			 struct fb_info *fb);
 static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
+			 struct fb_info *fb);
 static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
+			 struct fb_info *fb);
 static int atyfb_pan_display(struct fb_var_screeninfo *var, int con,
-			     struct fb_info *info);
+			     struct fb_info *fb);
 static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
 			  struct fb_info *info);
 static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
@@ -446,23 +247,50 @@
      *  Interface to the low level console driver
      */
 
-static int atyfbcon_switch(int con, struct fb_info *info);
-static int atyfbcon_updatevar(int con, struct fb_info *info);
-static void atyfbcon_blank(int blank, struct fb_info *info);
+static int atyfbcon_switch(int con, struct fb_info *fb);
+static int atyfbcon_updatevar(int con, struct fb_info *fb);
+static void atyfbcon_blank(int blank, struct fb_info *fb);
 
 
     /*
      *  Text console acceleration
      */
 
+static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx,
+			    int height, int width);
+static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy,
+			    int sx, int height, int width);
 #ifdef FBCON_HAS_CFB8
 static struct display_switch fbcon_aty8;
+static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c,
+			    int yy, int xx);
+static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
+			     const unsigned short *s, int count, int yy,
+			     int xx);
 #endif
 #ifdef FBCON_HAS_CFB16
 static struct display_switch fbcon_aty16;
+static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, int c,
+			     int yy, int xx);
+static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p,
+			      const unsigned short *s, int count, int yy,
+			      int xx);
+#endif
+#ifdef FBCON_HAS_CFB24
+static struct display_switch fbcon_aty24;
+static void fbcon_aty24_putc(struct vc_data *conp, struct display *p, int c,
+			     int yy, int xx);
+static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p,
+			      const unsigned short *s, int count, int yy,
+			      int xx);
 #endif
 #ifdef FBCON_HAS_CFB32
 static struct display_switch fbcon_aty32;
+static void fbcon_aty32_putc(struct vc_data *conp, struct display *p, int c,
+			     int yy, int xx);
+static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p,
+			      const unsigned short *s, int count, int yy,
+			      int xx);
 #endif
 
 
@@ -476,12 +304,72 @@
 static char *strtoke(char *s, const char *ct);
 #endif
 
+static void reset_engine(const struct fb_info_aty *info);
+static void init_engine(const struct atyfb_par *par,
+			const struct fb_info_aty *info);
+static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info);
+static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info);
+static void aty_set_crtc(const struct fb_info_aty *info,
+			 const struct crtc *crtc);
+static int aty_var_to_crtc(const struct fb_info_aty *info,
+			   const struct fb_var_screeninfo *var,
+			   struct crtc *crtc);
+static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp);
+static int aty_crtc_to_var(const struct crtc *crtc,
+			   struct fb_var_screeninfo *var);
+static void aty_set_pll_gx(const struct fb_info_aty *info,
+			   const struct pll_gx *pll);
+static int aty_var_to_pll_18818(const struct fb_var_screeninfo *var,
+				struct pll_gx *pll);
+static int aty_var_to_pll_514(const struct fb_var_screeninfo *var,
+			      struct pll_gx *pll);
+static int aty_pll_gx_to_var(const struct pll_gx *pll,
+			     struct fb_var_screeninfo *var);
+static void aty_set_pll_ct(const struct fb_info_aty *info,
+			   const struct pll_ct *pll);
+static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div,
+		      u8 mclk_post_div, u8 vclk_fb_div, u8 vclk_post_div,
+		      u8 bpp, struct pll_ct *pll);
+static int aty_var_to_pll_ct(const struct fb_info_aty *info,
+			     const struct fb_var_screeninfo *var,
+			     struct pll_ct *pll);
+static int aty_pll_ct_to_var(const struct pll_ct *pll,
+			     struct fb_var_screeninfo *var);
+static void atyfb_set_par(const struct atyfb_par *par,
+			  struct fb_info_aty *info);
+static int atyfb_decode_var(const struct fb_var_screeninfo *var,
+			    struct atyfb_par *par,
+			    const struct fb_info_aty *info);
+static int atyfb_encode_var(struct fb_var_screeninfo *var,
+			    const struct atyfb_par *par,
+			    const struct fb_info_aty *info);
+static void set_off_pitch(struct atyfb_par *par,
+			  const struct fb_info_aty *info);
+static int encode_fix(struct fb_fix_screeninfo *fix,
+		      const struct atyfb_par *par,
+		      const struct fb_info_aty *info);
 static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-			 u_int *transp, struct fb_info *info);
+			 u_int *transp, struct fb_info *fb);
 static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-			 u_int transp, struct fb_info *info);
+			 u_int transp, struct fb_info *fb);
 static void do_install_cmap(int con, struct fb_info *info);
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+static int read_aty_sense(const struct fb_info_aty *info);
+#endif
+
+
+    /*
+     *  Interface used by the world
+     */
+
+void atyfb_init(void);
+#ifdef CONFIG_FB_OF
+void atyfb_of_init(struct device_node *dp);
+#endif
+void atyfb_setup(char *options, int *ints);
+
 
+static int currcon = 0;
 
 static struct fb_ops atyfb_ops = {
     atyfb_open, atyfb_release, atyfb_get_fix, atyfb_get_var, atyfb_set_var,
@@ -493,64 +381,110 @@
 #endif
 };
 
+static char atyfb_name[16] = "ATY Mach64";
+static char fontname[40] __initdata = { 0 };
+
+static const u32 ref_clk_per = 1000000000000ULL/14318180;
+
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
+#endif
+
+#ifdef CONFIG_ATARI
+static unsigned int mach64_count __initdata = 0;
+static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, };
+static unsigned long phys_size[FB_MAX] __initdata = { 0, };
+static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
+#endif
+
+
+static struct aty_features {
+    u16 pci_id;
+    u16 chip_type;
+    const char *name;
+} aty_features[] __initdata = {
+    /* mach64GX family */
+    { 0x4758, 0x00d7, "mach64GX (ATI888GX00)" },
+    { 0x4358, 0x0057, "mach64CX (ATI888CX00)" },
+
+    /* mach64CT family */
+    { 0x4354, 0x4354, "mach64CT (ATI264CT)" },
+    { 0x4554, 0x4554, "mach64ET (ATI264ET)" },
+
+    /* mach64CT family / mach64VT class */
+    { 0x5654, 0x5654, "mach64VT (ATI264VT)" },
+    { 0x5655, 0x5655, "mach64VTB (ATI264VTB)" },
+/*  { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)" }, */
+
+    /* mach64CT family / mach64GT (3D RAGE) class */
+    { 0x4c54, 0x4c54, "3D RAGE LT" },
+    { 0x4c47, 0x4c47, "3D RAGE LG" },
+    { 0x4754, 0x4754, "3D RAGE (GT)" },
+    { 0x4755, 0x4755, "3D RAGE II+ (GTB)" },
+/*  { 0x4756, 0x4756, "3D RAGE IIC" }, */
+    { 0x4742, 0x4742, "3D RAGE PRO (BGA, AGP)" },
+    { 0x4744, 0x4744, "3D RAGE PRO (BGA, AGP, 1x only)" },
+    { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)" },
+    { 0x4750, 0x4750, "3D RAGE PRO (PQFP, PCI)" },
+    { 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)" },
+};
 
-static inline int aty_vram_reqd(const struct atyfb_par *par)
-{
-    return (par->vxres*par->vyres) << par->hw.gx.cmode;
-}
 
 static inline u32 aty_ld_le32(volatile unsigned int regindex,
-			      struct fb_info_aty *info)
+			      const struct fb_info_aty *info)
 {
     unsigned long temp;
     u32 val;
 
-#ifdef __powerpc__
+#if defined(__powerpc__)
     temp = info->ati_regbase;
-    asm("lwbrx %0,%1,%2": "=r"(val):"r"(regindex), "r"(temp));
-#else
-#ifdef __sparc__v9__
+    asm("lwbrx %0,%1,%2" : "=r"(val) : "r" (regindex), "r" (temp));
+#elif defined(__sparc_v9__)
     temp = info->ati_regbase + regindex;
     asm("lduwa [%1] %2, %0" : "=r" (val) : "r" (temp), "i" (ASI_PL));
 #else
     temp = info->ati_regbase+regindex;
     val = le32_to_cpu(*((volatile u32 *)(temp)));
 #endif
-#endif
     return val;
 }
 
 static inline void aty_st_le32(volatile unsigned int regindex, u32 val,
-			       struct fb_info_aty *info)
+			       const struct fb_info_aty *info)
 {
     unsigned long temp;
 
-#ifdef __powerpc__
+#if defined(__powerpc__)
     temp = info->ati_regbase;
-    asm("stwbrx %0,%1,%2": : "r"(val), "r"(regindex), "r"(temp):"memory");
-#else
-#ifdef __sparc__v9__
+    asm("stwbrx %0,%1,%2" : : "r" (val), "r" (regindex), "r" (temp) :
+	"memory");
+#elif defined(__sparc_v9__)
     temp = info->ati_regbase + regindex;
-    asm("stwa %0, [%1] %2" : "r" (val), "r" (temp), "i" (ASI_PL) : "memory");
+    asm("stwa %0, [%1] %2" : : "r" (val), "r" (temp), "i" (ASI_PL) : "memory");
 #else
     temp = info->ati_regbase+regindex;
     *((volatile u32 *)(temp)) = cpu_to_le32(val);
 #endif
-#endif
 }
 
 static inline u8 aty_ld_8(volatile unsigned int regindex,
-			  struct fb_info_aty *info)
+			  const struct fb_info_aty *info)
 {
     return *(volatile u8 *)(info->ati_regbase+regindex);
 }
 
 static inline void aty_st_8(volatile unsigned int regindex, u8 val,
-			    struct fb_info_aty *info)
+			    const struct fb_info_aty *info)
 {
     *(volatile u8 *)(info->ati_regbase+regindex) = val;
 }
 
+
+    /*
+     *  Generic Mach64 routines
+     */
+
     /*
      *  All writes to draw engine registers are automatically routed through a
      *  32-bit-wide, 16-entry-deep command FIFO ...
@@ -559,19 +493,19 @@
      *  (from Chapter 5 of the Mach64 Programmer's Guide)
      */
 
-static inline void wait_for_fifo(u16 entries, struct fb_info_aty *info)
+static inline void wait_for_fifo(u16 entries, const struct fb_info_aty *info)
 {
     while ((aty_ld_le32(FIFO_STAT, info) & 0xffff) >
 	   ((u32)(0x8000 >> entries)));
 }
 
-static inline void wait_for_idle(struct fb_info_aty *info)
+static inline void wait_for_idle(const struct fb_info_aty *info)
 {
     wait_for_fifo(16, info);
     while ((aty_ld_le32(GUI_STAT, info) & 1)!= 0);
 }
 
-static void reset_engine(struct fb_info_aty *info)
+static void reset_engine(const struct fb_info_aty *info)
 {
     /* reset engine */
     aty_st_le32(GEN_TEST_CNTL,
@@ -585,20 +519,19 @@
 			  BUS_FIFO_ERR_ACK, info);
 }
 
-static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info)
+static void init_engine(const struct atyfb_par *par,
+			const struct fb_info_aty *info)
 {
     u32 pitch_value;
 
     /* determine modal information from global mode structure */
-    pitch_value = par->vxres;
+    pitch_value = par->crtc.vxres;
 
-#if 0
-    if (par->hw.gx.cmode == CMODE_24) {
+    if (par->crtc.bpp == 24) {
 	/* In 24 bpp, the engine is in 8 bpp - this requires that all */
 	/* horizontal coordinates and widths must be adjusted */
 	pitch_value = pitch_value * 3;
     }
-#endif
 
     /* Reset engine, enable, and clear any engine errors */
     reset_engine(info);
@@ -655,7 +588,7 @@
     /* set scissors to modal size */
     aty_st_le32(SC_LEFT, 0, info);
     aty_st_le32(SC_TOP, 0, info);
-    aty_st_le32(SC_BOTTOM, par->vyres-1, info);
+    aty_st_le32(SC_BOTTOM, par->crtc.vyres-1, info);
     aty_st_le32(SC_RIGHT, pitch_value-1, info);
 
     /* set background color to minimum value (usually BLACK) */
@@ -684,48 +617,18 @@
 
     /* set pixel depth */
     wait_for_fifo(2, info);
-    switch(par->hw.gx.cmode) {
-#ifdef FBCON_HAS_CFB8
-	case CMODE_8:
-	    aty_st_le32(DP_PIX_WIDTH, HOST_8BPP | SRC_8BPP | DST_8BPP |
-				      BYTE_ORDER_LSB_TO_MSB,
-	    info);
-	    aty_st_le32(DP_CHAIN_MASK, 0x8080, info);
-	    break;
-#endif
-#ifdef FBCON_HAS_CFB16
-	case CMODE_16:
-	    aty_st_le32(DP_PIX_WIDTH, HOST_15BPP | SRC_15BPP | DST_15BPP |
-				      BYTE_ORDER_LSB_TO_MSB,
-	    info);
-	    aty_st_le32(DP_CHAIN_MASK, 0x4210, info);
-	    break;
-#endif
-#if 0
-	case CMODE_24:
-	    aty_st_le32(DP_PIX_WIDTH, HOST_8BPP | SRC_8BPP | DST_8BPP |
-				      BYTE_ORDER_LSB_TO_MSB,
-	    info);
-	    aty_st_le32(DP_CHAIN_MASK, 0x8080, info);
-	    break;
-#endif
-#ifdef FBCON_HAS_CFB32
-	case CMODE_32:
-	    aty_st_le32(DP_PIX_WIDTH, HOST_32BPP | SRC_32BPP | DST_32BPP |
-				      BYTE_ORDER_LSB_TO_MSB, info);
-	    aty_st_le32(DP_CHAIN_MASK, 0x8080, info);
-	    break;
-#endif
-    }
+    aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, info);
+    aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, info);
+
     /* insure engine is idle before leaving */
     wait_for_idle(info);
 }
 
-static void aty_st_514(int offset, u8 val, struct fb_info_aty *info)
+static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info)
 {
     aty_st_8(DAC_CNTL, 1, info);
     /* right addr byte */
-    aty_st_8(DAC_W_INDEX, offset & 0xff, info);	
+    aty_st_8(DAC_W_INDEX, offset & 0xff, info);
     /* left addr byte */
     aty_st_8(DAC_DATA, (offset >> 8) & 0xff, info);
     eieio();
@@ -734,7 +637,7 @@
     aty_st_8(DAC_CNTL, 0, info);
 }
 
-static void aty_st_pll(int offset, u8 val, struct fb_info_aty *info)
+static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info)
 {
     /* write addr byte */
     aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, info);
@@ -745,28 +648,28 @@
     aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info);
 }
 
-static struct aty_regvals *get_aty_struct(int vmode, struct fb_info_aty *info)
+#if 0 /* ecd debug */
+static u8 aty_ld_pll(int offset, const struct fb_info_aty *info)
 {
-    int v = vmode - 1;
+    u8 val;
 
-    switch (info->chip_class) {
-	case CLASS_GX:
-	    return aty_gx_reg_init[v];
-	    break;
-	case CLASS_CT:
-	case CLASS_VT:
-	    return aty_vt_reg_init[v];
-	    break;
-	case CLASS_GT:
-	    return aty_gt_reg_init[v];
-	    break;
-	default:
-	    /* should NOT happen */
-	    return NULL;
-    }
+    /* write addr byte */
+    aty_st_8(CLOCK_CNTL + 1, (offset << 2), info);
+    eieio();
+    /* read the register value */
+    val = aty_ld_8(CLOCK_CNTL + 2, info);
+    eieio();
+    return val;
 }
+#endif /* ecd debug */
+
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+
+    /*
+     *  Apple monitor sense
+     */
 
-static int read_aty_sense(struct fb_info_aty *info)
+static int read_aty_sense(const struct fb_info_aty *info)
 {
     int sense, i;
 
@@ -800,50 +703,13 @@
     return sense;
 }
 
-static void RGB514_Program(int cmode, struct fb_info_aty *info)
-{
-    typedef struct {
-	u8 pixel_dly;
-	u8 misc2_cntl;
-	u8 pixel_rep;
-	u8 pixel_cntl_index;
-	u8 pixel_cntl_v1;
-    } RGB514_DAC_Table;
-
-    static RGB514_DAC_Table RGB514DAC_Tab[8] = {
-	{0, 0x41, 0x03, 0x71, 0x45},	/* 8bpp */
-	{0, 0x45, 0x04, 0x0c, 0x01},	/* 555 */
-	{0, 0x45, 0x06, 0x0e, 0x00},	/* XRGB */
-    };
-    RGB514_DAC_Table *pDacProgTab;
-
-    pDacProgTab = &RGB514DAC_Tab[cmode];
-
-    aty_st_514(0x90, 0x00, info);
-    aty_st_514(0x04, pDacProgTab->pixel_dly, info);
-    aty_st_514(0x05, 0x00, info);
-
-    aty_st_514(0x2, 0x1, info);
-    aty_st_514(0x71, pDacProgTab->misc2_cntl, info);
-    aty_st_514(0x0a, pDacProgTab->pixel_rep, info);
-
-    aty_st_514(pDacProgTab->pixel_cntl_index, pDacProgTab->pixel_cntl_v1,
-	       info);
-}
-
-static void set_off_pitch(const struct atyfb_par *par,
-			  struct fb_info_aty *info)
-{
-    u32 pitch, offset;
+#endif /* defined(CONFIG_PMAC) || defined(CONFIG_CHRP) */
 
-    pitch = par->vxres>>3;
-    offset = ((par->yoffset*par->vxres+par->xoffset)>>3)<<par->hw.gx.cmode;
-    aty_st_le32(CRTC_OFF_PITCH, pitch<<22 | offset, info);
-}
+/* ------------------------------------------------------------------------- */
 
-/*
- * Hardware Cursor support.
- */
+    /*
+     *  Hardware Cursor support.
+     */
 
 static u8 cursor_pixel_map[2] = { 0, 15 };
 static u8 cursor_color_map[2] = { 0, 0xff };
@@ -870,6 +736,11 @@
 	if (!c)
 		return;
 
+#ifdef __sparc__
+	if (fb->mmaped && currcon == fb->vtconsole)
+		return;
+#endif
+
 	for (i = 0; i < 2; i++) {
 		c->color[i] =  (u32)red[i] << 24;
 		c->color[i] |= (u32)green[i] << 16;
@@ -880,7 +751,6 @@
 	wait_for_fifo(2, fb);
 	aty_st_le32(CUR_CLR0, c->color[0], fb);
 	aty_st_le32(CUR_CLR1, c->color[1], fb);
-	wait_for_idle(fb);
 }
 
 static void
@@ -893,6 +763,11 @@
 	if (!c)
 		return;
 
+#ifdef __sparc__
+	if (fb->mmaped && currcon == fb->vtconsole)
+		return;
+#endif
+
 	ram = (u8 *)(fb->frame_buffer + c->offset);
 
 	for (y = 0; y < c->size.y; y++) {
@@ -922,6 +797,11 @@
 	if (!c)
 		return;
 
+#ifdef __sparc__
+	if (fb->mmaped && currcon == fb->vtconsole)
+		return;
+#endif
+
 	if (c->on) {
 		x = c->pos.x - c->hot.x;
 		if (x < 0) {
@@ -952,7 +832,6 @@
 			    aty_ld_le32(GEN_TEST_CNTL, fb) & ~HWCURSOR_ENABLE,
 			    fb);
 	}
-	wait_for_idle(fb);
 }
 
 static void
@@ -986,6 +865,11 @@
 	if (!c)
 		return;
 
+#ifdef __sparc__
+	if (fb->mmaped && currcon == fb->vtconsole)
+		return;
+#endif
+
 	x *= d->fontwidth;
 	y *= d->fontheight;
 	if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->on)
@@ -1061,425 +945,799 @@
 }
 
 
-static void atyfb_set_par(struct atyfb_par *par, struct fb_info_aty *info)
-{
-    int i, j = 0, hres;
-    struct aty_regvals *init = get_aty_struct(par->hw.gx.vmode, info);
-    int vram_type = aty_ld_le32(CONFIG_STAT0, info) & 7;
-
-    if (init == 0)	/* paranoia, shouldn't get here */
-	panic("aty: display mode %d not supported", par->hw.gx.vmode);
-
-    info->current_par = *par;
-    hres = vmode_attrs[par->hw.gx.vmode-1].hres;
-
-    if (info->chip_class != CLASS_GT) {
-	i = aty_ld_le32(CRTC_GEN_CNTL, info);
-	aty_st_le32(CRTC_GEN_CNTL, i | CRTC_EXT_DISP_EN, info);
-    }
-
-    if (info->chip_class == CLASS_GX) {
-	i = aty_ld_le32(GEN_TEST_CNTL, info);
-	aty_st_le32(GEN_TEST_CNTL, i | GEN_OVR_OUTPUT_EN, info);
-    }
-
-    switch (info->chip_class) {
-	case CLASS_GX:
-	    RGB514_Program(par->hw.gx.cmode, info);
-	    wait_for_idle(info);
-	    aty_st_514(0x06, 0x02, info);
-	    aty_st_514(0x10, 0x01, info);
-	    aty_st_514(0x70, 0x01, info);
-	    aty_st_514(0x8f, 0x1f, info);
-	    aty_st_514(0x03, 0x00, info);
-	    aty_st_514(0x05, 0x00, info);
-	    aty_st_514(0x20, init->clock_val[0], info);
-	    aty_st_514(0x21, init->clock_val[1], info);
-	    break;
-	case CLASS_CT:
-	case CLASS_VT:
-	    aty_st_pll(VPLL_CNTL, 0xb5, info);
-	    aty_st_pll(PLL_REF_DIV, 0x2d, info);
-	    aty_st_pll(PLL_GEN_CNTL, 0x14, info);
-	    aty_st_pll(MCLK_FB_DIV, 0xbd, info);
-	    aty_st_pll(PLL_VCLK_CNTL, 0x0b, info);
-	    aty_st_pll(VCLK_POST_DIV, init->clock_val[0], info);
-	    aty_st_pll(VCLK0_FB_DIV, init->clock_val[1], info);
-	    aty_st_pll(VCLK1_FB_DIV, 0xd6, info);
-	    aty_st_pll(VCLK2_FB_DIV, 0xee, info);
-	    aty_st_pll(VCLK3_FB_DIV, 0xf8, info);
-	    aty_st_pll(PLL_EXT_CNTL, 0x0, info);
-	    aty_st_pll(PLL_TEST_CTRL, 0x0, info);
-	    aty_st_pll(PLL_TEST_COUNT, 0x0, info);
-	    break;
-	case CLASS_GT:
-	    if (vram_type == 5) {
-		aty_st_pll(MPLL_CNTL, 0xcd, info);
-		aty_st_pll(VPLL_CNTL,
-			   par->hw.gx.vmode >= VMODE_1024_768_60 ? 0xd3
-								 : 0xd5,
-			   info);
-		aty_st_pll(PLL_REF_DIV, 0x21, info);
-		aty_st_pll(PLL_GEN_CNTL, 0x44, info);
-		aty_st_pll(MCLK_FB_DIV, 0xe8, info);
-		aty_st_pll(PLL_VCLK_CNTL, 0x03, info);
-		aty_st_pll(VCLK_POST_DIV, init->offset[0], info);
-		aty_st_pll(VCLK0_FB_DIV, init->offset[1], info);
-		aty_st_pll(VCLK1_FB_DIV, 0x8e, info);
-		aty_st_pll(VCLK2_FB_DIV, 0x9e, info);
-		aty_st_pll(VCLK3_FB_DIV, 0xc6, info);
-		aty_st_pll(PLL_EXT_CNTL, init->offset[2], info);
-		aty_st_pll(DLL_CNTL, 0xa6, info);
-		aty_st_pll(VFC_CNTL, 0x1b, info);
-	    } else {
-		aty_st_pll(VPLL_CNTL, 0xd5, info);
-		aty_st_pll(PLL_REF_DIV, 0x21, info);
-		aty_st_pll(PLL_GEN_CNTL, 0xc4, info);
-		aty_st_pll(MCLK_FB_DIV, 0xda, info);
-		aty_st_pll(PLL_VCLK_CNTL, 0x03, info);
-		/* offset actually holds clock values */
-		aty_st_pll(VCLK_POST_DIV, init->offset[0], info);
-		aty_st_pll(VCLK0_FB_DIV, init->offset[1], info);
-		aty_st_pll(VCLK1_FB_DIV, 0x8e, info);
-		aty_st_pll(VCLK2_FB_DIV, 0x9e, info);
-		aty_st_pll(VCLK3_FB_DIV, 0xc6, info);
-		aty_st_pll(PLL_TEST_CTRL, 0x0, info);
-		aty_st_pll(PLL_EXT_CNTL, init->offset[2], info);
-		aty_st_pll(DLL_CNTL, 0xa0, info);
-		aty_st_pll(VFC_CNTL, 0x1b, info);
-	    }
-	    break;
-    }
 
-    aty_ld_8(DAC_REGS, info);	/* clear counter */
-    wait_for_idle(info);
 
-    aty_st_le32(CRTC_H_TOTAL_DISP, init->crtc_h_tot_disp, info);
-    aty_st_le32(CRTC_H_SYNC_STRT_WID,
-		init->crtc_h_sync_strt_wid[par->hw.gx.cmode], info);
-    aty_st_le32(CRTC_V_TOTAL_DISP, init->crtc_v_tot_disp, info);
-    aty_st_le32(CRTC_V_SYNC_STRT_WID, init->crtc_v_sync_strt_wid, info);
+/* ------------------------------------------------------------------------- */
 
-    aty_st_8(CLOCK_CNTL, 0, info);
-    aty_st_8(CLOCK_CNTL, CLOCK_STROBE, info);
+    /*
+     *  CRTC programming
+     */
 
+static void aty_set_crtc(const struct fb_info_aty *info,
+			 const struct crtc *crtc)
+{
+    aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, info);
+    aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, info);
+    aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, info);
+    aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, info);
     aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, info);
+    aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, info);
+    aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, info);
+}
 
-    set_off_pitch(par, info);
-
-    switch (info->chip_class) {
-	case CLASS_GX:
-	    /* The magic constant below translates into:
-	     * 5  = No RDY delay, 1 wait st for mem write, increment during
-	     *      burst transfer
-	     * 9  = DAC access delayed, 1 wait state for DAC
-	     * 0  = Disables interupts for FIFO errors
-	     * e  = Allows FIFO to generate 14 wait states before generating
-	     *      error
-	     * 1  = DAC snooping disabled, ROM disabled
-	     * 0  = ROM page at 0 (disabled so doesn't matter)
-	     * f  = 15 ROM wait states (disabled so doesn't matter)
-	     * f  = 15 BUS wait states (I'm not sure this applies to PCI bus
-	     *      types)
-	     * at some point it would be good to experiment with bench marks to
-	     * if we can gain some speed by fooling with the wait states etc.
-	     */
-	    aty_st_le32(BUS_CNTL, 0x890e20f1 /* 0x590e10ff */, info);
-	    j = 0x47012100;
-	    j = 0x47052100;
-	    break;
-
-	case CLASS_VT:
-	    if (vram_type == 4) {
-		/*
-		 * What to do here? - The contents of MEM_CNTL do not
-		 * seem to match my documentation, and touching this
-		 * register makes the output unusable.
-		 * (green bars across the screen and similar effects).
-		 *
-		 * Eddie C. Dost  (ecd@skynet.be)
-		 */
-		j = 0x87010184;
-		break;
-	     }
-	     /* fallthrough */
+static int aty_var_to_crtc(const struct fb_info_aty *info,
+			   const struct fb_var_screeninfo *var,
+			   struct crtc *crtc)
+{
+    u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp;
+    u32 left, right, upper, lower, hslen, vslen, sync, vmode;
+    u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
+    u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol;
+    u32 pix_width, dp_pix_width, dp_chain_mask;
+
+    /* input */
+    xres = var->xres;
+    yres = var->yres;
+    vxres = var->xres_virtual;
+    vyres = var->yres_virtual;
+    xoffset = var->xoffset;
+    yoffset = var->yoffset;
+    bpp = var->bits_per_pixel;
+    left = var->left_margin;
+    right = var->right_margin;
+    upper = var->upper_margin;
+    lower = var->lower_margin;
+    hslen = var->hsync_len;
+    vslen = var->vsync_len;
+    sync = var->sync;
+    vmode = var->vmode;
+
+    /* convert (and round up) and validate */
+    xres = (xres+7) & ~7;
+    xoffset = (xoffset+7) & ~7;
+    vxres = (vxres+7) & ~7;
+    if (vxres < xres+xoffset)
+	vxres = xres+xoffset;
+    h_disp = xres/8-1;
+    if (h_disp > 0xff)
+	FAIL("h_disp too large");
+    h_sync_strt = h_disp+(right/8);
+    if (h_sync_strt > 0x1ff)
+	FAIL("h_sync_start too large");
+    h_sync_dly = right & 7;
+    h_sync_wid = (hslen+7)/8;
+    if (h_sync_wid > 0x1f)
+	FAIL("h_sync_wid too large");
+    h_total = h_sync_strt+h_sync_wid+(h_sync_dly+left+7)/8;
+    if (h_total > 0x1ff)
+	FAIL("h_total too large");
+    h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
+
+    if (vyres < yres+yoffset)
+	vyres = yres+yoffset;
+    v_disp = yres-1;
+    if (v_disp > 0x7ff)
+	FAIL("v_disp too large");
+    v_sync_strt = v_disp+lower;
+    if (v_sync_strt > 0x7ff)
+	FAIL("v_sync_strt too large");
+    v_sync_wid = vslen;
+    if (v_sync_wid > 0x1f)
+	FAIL("v_sync_wid too large");
+    v_total = v_sync_strt+v_sync_wid+upper;
+    if (v_total > 0x7ff)
+	FAIL("v_total too large");
+    v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
+
+    if (bpp <= 8) {
+	bpp = 8;
+	pix_width = CRTC_PIX_WIDTH_8BPP;
+	dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB;
+	dp_chain_mask = 0x8080;
+    } else if (bpp <= 16) {
+	bpp = 16;
+	pix_width = CRTC_PIX_WIDTH_15BPP;
+	dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP |
+		       BYTE_ORDER_LSB_TO_MSB;
+	dp_chain_mask = 0x4210;
+    } else if ((bpp <= 24) && (Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
+	bpp = 24;
+	pix_width = CRTC_PIX_WIDTH_24BPP;
+	dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB;
+	dp_chain_mask = 0x8080;
+    } else if (bpp <= 32) {
+	bpp = 32;
+	pix_width = CRTC_PIX_WIDTH_32BPP;
+	dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP |
+		       BYTE_ORDER_LSB_TO_MSB;
+	dp_chain_mask = 0x8080;
+    } else
+	FAIL("invalid bpp");
 
-	case CLASS_CT:
-	    aty_st_le32(BUS_CNTL, 0x680000f9, info);
-	    switch (info->total_vram) {
-		case 0x00100000:
-		    aty_st_le32(MEM_CNTL, vt_mem_cntl[0][par->hw.gx.cmode],
-				info);
-		    break;
-		case 0x00200000:
-		    aty_st_le32(MEM_CNTL, vt_mem_cntl[1][par->hw.gx.cmode],
-				info);
-		    break;
-		case 0x00400000:
-		    aty_st_le32(MEM_CNTL, vt_mem_cntl[2][par->hw.gx.cmode],
-				info);
-		    break;
-		default:
-		    i = aty_ld_le32(MEM_CNTL, info) & 0x000F;
-		    aty_st_le32(MEM_CNTL,
-				(init->mem_cntl[par->hw.gx.cmode] &
-				 0xFFFFFFF0) | i,
-				info);
-	    }
-	    j = 0x87010184;
-	    break;
+    if (vxres*vyres*bpp/8 > info->total_vram)
+	FAIL("not enough video RAM");
 
-	case CLASS_GT:
-	    aty_st_le32(BUS_CNTL, 0x7b23a040, info);
+    if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+	FAIL("invalid vmode");
 
-	    /* need to set DSP values !! assume sdram */
-	    i = init->crtc_gen_cntl[0] - (0x100000 * par->hw.gx.cmode);
-	    if ( vram_type == 5 )
-		i = init->crtc_gen_cntl[1] - (0x100000 * par->hw.gx.cmode);
-	    aty_st_le32(DSP_CONFIG, i, info);
-
-	    i = aty_ld_le32(MEM_CNTL, info) & MEM_SIZE_ALIAS;
-	    if ( vram_type == 5 ) {
-		i |= ((1 * par->hw.gx.cmode) << 26) | 0x4215b0;
-		aty_st_le32(DSP_ON_OFF,
-			    sgram_dsp[par->hw.gx.vmode-1][par->hw.gx.cmode],
-			    info);
+    /* output */
+    crtc->vxres = vxres;
+    crtc->vyres = vyres;
+    crtc->xoffset = xoffset;
+    crtc->yoffset = yoffset;
+    crtc->bpp = bpp;
+    crtc->h_tot_disp = h_total | (h_disp<<16);
+    crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly<<8) |
+			    ((h_sync_strt & 0x100)<<4) | (h_sync_wid<<16) |
+			    (h_sync_pol<<21);
+    crtc->v_tot_disp = v_total | (v_disp<<16);
+    crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<21);
+    crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
+    crtc->gen_cntl = pix_width | CRTC_EXT_DISP_EN | CRTC_ENABLE;
+    if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID) ||
+	((Gx == VT_CHIP_ID) && !(Rev & 0x03)) ||
+	((Gx == GT_CHIP_ID) && !(Rev & 0x03))) {
+	/* Not VTB/GTB */
+	/* FIXME: magic FIFO values */
+	crtc->gen_cntl |= aty_ld_le32(CRTC_GEN_CNTL, info) & 0x000e0000;
+    }
+    crtc->dp_pix_width = dp_pix_width;
+    crtc->dp_chain_mask = dp_chain_mask;
 
-		/* aty_st_le32(CLOCK_CNTL, 8192, info); */
-	    } else {
-		i |= ((1 * par->hw.gx.cmode) << 26) | 0x300090;
-		aty_st_le32(DSP_ON_OFF, init->mem_cntl[par->hw.gx.cmode],
-			    info);
-	    }
-	    aty_st_le32(MEM_CNTL, i, info);
-	    aty_st_le32(EXT_MEM_CNTL, 0x5000001, info);
+    return 0;
+}
 
-	    /* if (info->total_vram > 0x400000)	
-		i |= 0x538; this not been verified on > 4Megs!! */
+static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp)
+{
+    static struct {
+	u8 pixel_dly;
+	u8 misc2_cntl;
+	u8 pixel_rep;
+	u8 pixel_cntl_index;
+	u8 pixel_cntl_v1;
+    } tab[3] = {
+	{ 0, 0x41, 0x03, 0x71, 0x45 },	/* 8 bpp */
+	{ 0, 0x45, 0x04, 0x0c, 0x01 },	/* 555 */
+	{ 0, 0x45, 0x06, 0x0e, 0x00 },	/* XRGB */
+    };
+    int i;
 
-	    j = 0x86010102;
+    switch (bpp) {
+	case 8:
+	default:
+	    i = 0;
+	    break;
+	case 16:
+	    i = 1;
+	    break;
+	case 32:
+	    i = 2;
 	    break;
     }
+    aty_st_514(0x90, 0x00, info);		/* VRAM Mask Low */
+    aty_st_514(0x04, tab[i].pixel_dly, info);	/* Horizontal Sync Control */
+    aty_st_514(0x05, 0x00, info);		/* Power Management */
+    aty_st_514(0x02, 0x01, info);		/* Misc Clock Control */
+    aty_st_514(0x71, tab[i].misc2_cntl, info);	/* Misc Control 2 */
+    aty_st_514(0x0a, tab[i].pixel_rep, info);	/* Pixel Format */
+    aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, info);
+			/* Misc Control 2 / 16 BPP Control / 32 BPP Control */
+}
+
+static int aty_crtc_to_var(const struct crtc *crtc,
+			   struct fb_var_screeninfo *var)
+{
+    u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync;
+    u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
+    u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol;
+    u32 pix_width;
+
+    /* input */
+    h_total = crtc->h_tot_disp & 0x1ff;
+    h_disp = (crtc->h_tot_disp>>16) & 0xff;
+    h_sync_strt = (crtc->h_sync_strt_wid & 0xff) |
+		  ((crtc->h_sync_strt_wid>>4) & 0x100);
+    h_sync_dly = (crtc->h_sync_strt_wid>>8) & 0x7;
+    h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x1f;
+    h_sync_pol = (crtc->h_sync_strt_wid>>21) & 0x1;
+    v_total = crtc->v_tot_disp & 0x7ff;
+    v_disp = (crtc->v_tot_disp>>16) & 0x7ff;
+    v_sync_strt = crtc->v_sync_strt_wid & 0x7ff;
+    v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f;
+    v_sync_pol = (crtc->v_sync_strt_wid>>21) & 0x1;
+    pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;
+
+    /* convert */
+    xres = (h_disp+1)*8;
+    yres = v_disp+1;
+    left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly;
+    right = (h_sync_strt-h_disp)*8;
+    hslen = h_sync_wid*8;
+    upper = v_total-v_sync_strt-v_sync_wid;
+    lower = v_sync_strt-v_disp;
+    vslen = v_sync_wid;
+    sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
+	   (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT);
 
-    /* These magic constants (variable j) are harder to figure out
-    * on the vt chipset bit 2 set makes the screen brighter
-    * and bit 15 makes the screen black! But nothing else
-    * seems to matter for the vt DAC_CNTL
-    */
-    aty_st_le32(DAC_CNTL, j, info);
-    aty_st_8(DAC_MASK, 0xff, info);
-
-    switch (par->hw.gx.cmode) {
-	case CMODE_16:
-	    i = CRTC_PIX_WIDTH_15BPP; break;
-	/*case CMODE_24: */
-	case CMODE_32:
-	    i = CRTC_PIX_WIDTH_32BPP; break;
-	case CMODE_8:
+    switch (pix_width) {
+#if 0
+	case CRTC_PIX_WIDTH_4BPP:
+	    bpp = 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;
+	    break;
+#endif
+	case CRTC_PIX_WIDTH_8BPP:
+	    bpp = 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;
+	    break;
+	case CRTC_PIX_WIDTH_15BPP:	/* RGB 555 */
+	    bpp = 16;
+	    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 = 0;
+	    var->transp.length = 0;
+	    break;
+#if 0
+	case CRTC_PIX_WIDTH_16BPP:	/* RGB 565 */
+	    bpp = 16;
+	    var->red.offset = 11;
+	    var->red.length = 5;
+	    var->green.offset = 6;
+	    var->green.length = 6;
+	    var->blue.offset = 0;
+	    var->blue.length = 5;
+	    var->transp.offset = 0;
+	    var->transp.length = 0;
+	    break;
+#endif
+	case CRTC_PIX_WIDTH_24BPP:	/* RGB 888 */
+	    bpp = 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;
+	    break;
+	case CRTC_PIX_WIDTH_32BPP:	/* ARGB 8888 */
+	    bpp = 32;
+	    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;
+	    break;
 	default:
-	    i = CRTC_PIX_WIDTH_8BPP; break;
+	    FAIL("Invalid pixel width");
     }
 
-    if (info->chip_class != CLASS_GT) {
-	aty_st_le32(CRTC_INT_CNTL, 0x00000002, info);
-	aty_st_le32(GEN_TEST_CNTL, GUI_ENGINE_ENABLE | BLOCK_WRITE_ENABLE,
-		    info);	/* gui_en block_en */
-	i |= init->crtc_gen_cntl[par->hw.gx.cmode];
-    }
-    /* Gentlemen, start your crtc engine */
-    aty_st_le32(CRTC_GEN_CNTL, CRTC_EXT_DISP_EN | CRTC_ENABLE | i, info);
-
-    /* Initialize the graphics engine */
-    if (par->accel & FB_ACCELF_TEXT)
-	init_engine(par, info);
+    /* output */
+    var->xres = xres;
+    var->yres = yres;
+    var->xres_virtual = crtc->vxres;
+    var->yres_virtual = crtc->vyres;
+    var->bits_per_pixel = bpp;
+    var->xoffset = crtc->xoffset;
+    var->yoffset = crtc->yoffset;
+    var->left_margin = left;
+    var->right_margin = right;
+    var->upper_margin = upper;
+    var->lower_margin = lower;
+    var->hsync_len = hslen;
+    var->vsync_len = vslen;
+    var->sync = sync;
+    var->vmode = FB_VMODE_NONINTERLACED;
 
-#ifdef CONFIG_FB_COMPAT_XPMAC
-    if (console_fb_info == &info->fb_info) {
-	display_info.height = vmode_attrs[par->hw.gx.vmode-1].vres;
-	display_info.width = vmode_attrs[par->hw.gx.vmode-1].hres;
-	display_info.depth = 8<<par->hw.gx.cmode;
-	display_info.pitch = par->vxres<<par->hw.gx.cmode;
-	display_info.mode = par->hw.gx.vmode;
-	strcpy(display_info.name, atyfb_name);
-	display_info.fb_address = info->frame_buffer_phys;
-	if (info->chip_class == CLASS_VT)
-	    display_info.fb_address += init->offset[par->hw.gx.cmode];
-	display_info.cmap_adr_address = info->ati_regbase_phys+0xc0;
-	display_info.cmap_data_address = info->ati_regbase_phys+0xc1;
-	display_info.disp_reg_address = info->ati_regbase_phys;
-    }
-#endif /* CONFIG_FB_COMPAT_XPMAC */
+    return 0;
 }
 
+/* ------------------------------------------------------------------------- */
 
     /*
-     *  Open/Release the frame buffer device
+     *  PLL programming (Mach64 GX family)
+     *
+     *  FIXME: use function pointer tables instead of switch statements
      */
 
-static int atyfb_open(struct fb_info *info, int user)
+static void aty_set_pll_gx(const struct fb_info_aty *info,
+			   const struct pll_gx *pll)
+{
+    switch (info->clk_type) {
+	case CLK_ATI18818_1:
+	    aty_st_8(CLOCK_CNTL, pll->m, info);
+	    break;
+	case CLK_IBMRGB514:
+	    aty_st_514(0x06, 0x02, info);	/* DAC Operation */
+	    aty_st_514(0x10, 0x01, info);	/* PLL Control 1 */
+	    aty_st_514(0x70, 0x01, info);	/* Misc Control 1 */
+	    aty_st_514(0x8f, 0x1f, info);	/* PLL Ref. Divider Input */
+	    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 */
+	    break;
+    }
+}
+
+static int aty_var_to_pll_18818(const struct fb_var_screeninfo *var,
+				struct pll_gx *pll)
+{
+    /*
+     *  FIXME: use real calculations instead of using fixed values from the old
+     *	       driver
+     */
+    static struct {
+	u32 ps_lim;	/* pixclock period rounding limit (arbitrary) */
+	u8 mode;	/* (prescsaler << 4) | Select */
+	u8 prog;	/* ref_div_count */
+    } ATI18818_clocks[] = {
+	{  7500, 0x0B, 1 },	/*  7407.4 ps = 135.00 MHz */
+	{  9000, 0x0A, 1 },	/*  7936.5 ps = 126.00 MHz */
+	{ 11000, 0x09, 1 },	/* 10000.0 ps = 100.00 MHz */
+	{ 12800, 0x0D, 1 },	/* 12500.0 ps =  80.00 MHz */
+	{ 13500, 0x0E, 1 },	/* 13333.3 ps =  75.00 MHz */
+/*	{ 14000, 0x03, 2 },*/	/* 13888.8 ps =  72.00 MHz */
+	{ 15000, 0x1B, 1 },	/* 14814.8 ps =  67.50 MHz */
+	{ 15500, 0x0F, 1 },	/* 15384.6 ps =  65.00 MHz */
+	{ 16000, 0x1A, 1 },	/* 15873.0 ps =  63.00 MHz */
+/*	{ 16000, 0x02, 2 },*/	/* 15873.0 ps =  63.00 MHz */
+/*	{ 18000, 0x01, 2 },*/	/* 17655.4 ps =  56.64 MHz */
+/*	{ 19900, 0x00, 2 },*/	/* 19860.9 ps =  50.35 MHz */
+	{ 20000, 0x07, 1 },	/* 20000.0 ps =  50.00 MHz */
+	{ 20300, 0x06, 1 },	/* 20202.0 ps =  49.50 MHz */
+	{ 22500, 0x05, 1 },	/* 22271.2 ps =  44.90 MHz */
+	{ 25000, 0x04, 1 },	/* 25000.0 ps =  40.00 MHz */
+/*	{ 28000, 0x03, 1 },*/	/* 27777.8 ps =  36.00 MHz */
+	{ 30000, 0x2B, 1 },	/* 29629,6 ps =  33.75 MHz */
+	{ 31000, 0x1F, 1 },	/* 30769.2 ps =  32.50 MHz */
+	{ 32000, 0x2A, 1 },	/* 31746.0 ps =  31.50 MHz */
+/*	{ 32000, 0x02, 1 },*/	/* 31746.0 ps =  31.50 MHz */
+/*	{ 36000, 0x01, 1 },*/	/* 35310.7 ps =  28.32 MHz */
+/*	{ 39900, 0x00, 1 },*/	/* 39714.1 ps =  25.18 MHz */
+	{ 40000, 0x17, 1 },	/* 40000.0 ps =  25.00 MHz */
+	{ 40600, 0x16, 1 },	/* 40404.0 ps =  24.75 MHz */
+	{ 45000, 0x15, 1 },	/* 44543.4 ps =  22.45 MHz */
+	{ 50000, 0x14, 1 },	/* 50000.0 ps =  20.00 MHz */
+/*	{ 56000, 0x13, 1 },*/	/* 55555.5 ps =  18.00 MHz */
+	{ 62000, 0x2F, 1 },	/* 61538.8 ps =  16.25 MHz */
+/*	{ 64000, 0x12, 1 },*/	/* 63492.0 ps =  15.75 MHz */
+    };
+    int set;
 
+    for (set = 0; set < sizeof(ATI18818_clocks)/sizeof(*ATI18818_clocks);
+	 set++)
+	if (var->pixclock <= ATI18818_clocks[set].ps_lim) {
+	    pll->m = ATI18818_clocks[set].mode;
+	    pll->n = ATI18818_clocks[set].prog;
+	    return 0;
+	}
+    return -EINVAL;
+}
+
+static int aty_var_to_pll_514(const struct fb_var_screeninfo *var,
+			      struct pll_gx *pll)
 {
     /*
-     *  Nothing, only a usage count for the moment
+     *  FIXME: use real calculations instead of using fixed values from the old
+     *	       driver
      */
+    static struct {
+	u32 limit;	/* pixlock rounding limit (arbitrary) */
+	u8 m;		/* (df<<6) | vco_div_count */
+	u8 n;		/* ref_div_count */
+    } RGB514_clocks[7] = {
+	{  8000, (3<<6) | 20, 9 },	/*  7395 ps / 135.2273 MHz */
+	{ 10000, (1<<6) | 19, 3 },	/*  9977 ps / 100.2273 MHz */
+	{ 13000, (1<<6) |  2, 3 },	/* 12509 ps /  79.9432 MHz */
+	{ 14000, (2<<6) |  8, 7 },	/* 13394 ps /  74.6591 MHz */
+	{ 16000, (1<<6) | 44, 6 },	/* 15378 ps /  65.0284 MHz */
+	{ 25000, (1<<6) | 15, 5 },	/* 17460 ps /  57.2727 MHz */
+	{ 50000, (0<<6) | 53, 7 },	/* 33145 ps /  30.1705 MHz */
+    };
+    int i;
 
-    MOD_INC_USE_COUNT;
-    return(0);
+    for (i = 0; i < sizeof(RGB514_clocks)/sizeof(*RGB514_clocks); i++)
+	if (var->pixclock <= RGB514_clocks[i].limit) {
+	    pll->m = RGB514_clocks[i].m;
+	    pll->n = RGB514_clocks[i].n;
+	    return 0;
+	}
+    return -EINVAL;
 }
 
-static int atyfb_release(struct fb_info *info, int user)
+    /* FIXME: ATI18818?? */
+
+static int aty_pll_gx_to_var(const struct pll_gx *pll,
+			     struct fb_var_screeninfo *var)
 {
-    MOD_DEC_USE_COUNT;
-    return(0);
-}
+    u8 df, vco_div_count, ref_div_count;
 
+    df = pll->m >> 6;
+    vco_div_count = pll->m & 0x3f;
+    ref_div_count = pll->n;
 
-static int encode_fix(struct fb_fix_screeninfo *fix,
-		      const struct atyfb_par *par, struct fb_info_aty *info)
-{
-    struct aty_regvals *init;
+    var->pixclock = (ref_clk_per*(vco_div_count+65)/ref_div_count)>>(3-df);
 
-    memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+    return 0;
+}
 
-    strcpy(fix->id, atyfb_name);
-    init = get_aty_struct(par->hw.gx.vmode, info);
-    /*
-     *  FIXME: This will cause problems on non-GT chips, because the frame
-     *  buffer must be aligned to a page
-     */
-    fix->smem_start = (char *)info->frame_buffer_phys;
-    if (info->chip_class == CLASS_VT)
-	fix->smem_start += init->offset[par->hw.gx.cmode];
-    fix->smem_len = (u32)info->total_vram;
 
-#ifdef __LITTLE_ENDIAN
     /*
-     *  Last page of 8 MB little-endian aperture is MMIO
-     *  FIXME: we should use the auxillary aperture instead so we can acces the
-     *  full 8 MB of video RAM on 8 MB boards
+     *  PLL programming (Mach64 CT family)
      */
-    if (fix->smem_len > 0x800000-PAGE_SIZE)
-	fix->smem_len = 0x800000-PAGE_SIZE;
-#endif
-    /*
-     *  Reg Block 0 (CT-compatible block) is at ati_regbase_phys
-     *  Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400
-     */
-    switch (info->chip_class) {
-	case CLASS_GX:
-	    fix->mmio_start = (char *)info->ati_regbase_phys;
-	    fix->mmio_len = 0x400;
-	    fix->accel = FB_ACCEL_ATI_MACH64GX;
-	    break;
-	case CLASS_CT:
-	    fix->mmio_start = (char *)info->ati_regbase_phys;
-	    fix->mmio_len = 0x400;
-	    fix->accel = FB_ACCEL_ATI_MACH64CT;
-	    break;
-	case CLASS_VT:
-	    fix->mmio_start = (char *)(info->ati_regbase_phys-0x400);
-	    fix->mmio_len = 0x800;
-	    fix->accel = FB_ACCEL_ATI_MACH64VT;
-	    break;
-	case CLASS_GT:
-	    fix->mmio_start = (char *)(info->ati_regbase_phys-0x400);
-	    fix->mmio_len = 0x800;
-	    fix->accel = FB_ACCEL_ATI_MACH64GT;
-	    break;
-	default:
-	    fix->mmio_start = NULL;
-	    fix->mmio_len = 0;
-	    fix->accel = 0;
+
+static void aty_set_pll_ct(const struct fb_info_aty *info,
+			   const struct pll_ct *pll)
+{
+#if 0 /* ecd debug */
+printk("PLL_REF_DIV:   %02x (%02x)\n",
+	pll->pll_ref_div, aty_ld_pll(PLL_REF_DIV, info));
+printk("PLL_GEN_CNTL:  %02x (%02x)\n",
+	pll->pll_gen_cntl, aty_ld_pll(PLL_GEN_CNTL, info));
+printk("MCLK_FB_DIV:   %02x (%02x)\n",
+	pll->mclk_fb_div, aty_ld_pll(MCLK_FB_DIV, info));
+printk("PLL_VCLK_CNTL: %02x (%02x)\n",
+	pll->pll_vclk_cntl, aty_ld_pll(PLL_VCLK_CNTL, info));
+printk("VCLK_POST_DIV: %02x (%02x)\n",
+	pll->vclk_post_div, aty_ld_pll(VCLK_POST_DIV, info));
+printk("VCLK0_FB_DIV:  %02x (%02x)\n",
+	pll->vclk_fb_div, aty_ld_pll(VCLK0_FB_DIV, info));
+printk("PLL_EXT_CNTL:  %02x (%02x)\n",
+	pll->pll_ext_cntl, aty_ld_pll(PLL_EXT_CNTL, info));
+#endif /* ecd debug */
+    aty_st_pll(PLL_REF_DIV, pll->pll_ref_div, info);
+    aty_st_pll(PLL_GEN_CNTL, pll->pll_gen_cntl, info);
+    aty_st_pll(MCLK_FB_DIV, pll->mclk_fb_div, info);
+    aty_st_pll(PLL_VCLK_CNTL, pll->pll_vclk_cntl, info);
+    aty_st_pll(VCLK_POST_DIV, pll->vclk_post_div, info);
+    aty_st_pll(VCLK0_FB_DIV, pll->vclk_fb_div, info);
+    aty_st_pll(PLL_EXT_CNTL, pll->pll_ext_cntl, info);
+
+    if (((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_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) ||
+	(Gx == VU_CHIP_ID)) {
+	if (info->ram_type >= SDRAM)
+	    aty_st_pll(DLL_CNTL, 0xa6, info);
+	else
+	    aty_st_pll(DLL_CNTL, 0xa0, info);
+	aty_st_pll(VFC_CNTL, 0x1b, info);
+	aty_st_le32(DSP_CONFIG, pll->dsp_config, info);
+	aty_st_le32(DSP_ON_OFF, pll->dsp_on_off, info);
+    }
+}
+
+static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div,
+		      u8 mclk_post_div, u8 vclk_fb_div, u8 vclk_post_div,
+		      u8 bpp, struct pll_ct *pll)
+{
+    u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off, dsp_on;
+    u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size, page_size;
+
+    /* xclocks_per_row<<11 */
+    xclks_per_row = (mclk_fb_div*vclk_post_div*64<<11)/
+		    (vclk_fb_div*mclk_post_div*bpp);
+    if (xclks_per_row < (1<<11))
+	FAIL("Dotclock to high");
+    fifo_size = 24;
+    dsp_precision = 0;
+    y = (xclks_per_row*fifo_size)>>11;
+    while (y) {
+	y >>= 1;
+	dsp_precision++;
+    }
+    dsp_precision -= 5;
+    /* fifo_off<<6 */
+    fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(1<<6);
+
+    if (info->total_vram > 1*1024*1024) {
+	if (info->ram_type >= SDRAM) {
+	    /* >1 MB SDRAM */
+	    dsp_loop_latency = 8;
+	    page_size = 8;
+	} else {
+	    /* >1 MB DRAM */
+	    dsp_loop_latency = 6;
+	    page_size = 9;
+	}
+    } else {
+	if (info->ram_type >= SDRAM) {
+	    /* <2 MB SDRAM */
+	    dsp_loop_latency = 9;
+	    page_size = 10;
+	} else {
+	    /* <2 MB DRAM */
+	    dsp_loop_latency = 8;
+	    page_size = 10;
+	}
     }
-    fix->type = FB_TYPE_PACKED_PIXELS;
-    fix->type_aux = 0;
-    fix->line_length = par->vxres<<par->hw.gx.cmode;
-    fix->visual = par->hw.gx.cmode == CMODE_8 ? FB_VISUAL_PSEUDOCOLOR
-					      : FB_VISUAL_TRUECOLOR;
-    fix->ywrapstep = 0;
-    fix->xpanstep = 8;
-    fix->ypanstep = 1;
+    /* fifo_on<<6 */
+    if (xclks_per_row >= (page_size<<11))
+	fifo_on = ((2*page_size+1)<<6)+(xclks_per_row>>5);
+    else
+	fifo_on = (3*page_size)<<6;
 
+    dsp_xclks_per_row = xclks_per_row>>dsp_precision;
+    dsp_on = fifo_on>>dsp_precision;
+    dsp_off = fifo_off>>dsp_precision;
+
+    pll->dsp_config = (dsp_xclks_per_row & 0x3fff) |
+		      ((dsp_loop_latency & 0xf)<<16) |
+		      ((dsp_precision & 7)<<20);
+    pll->dsp_on_off = (dsp_on & 0x7ff) | ((dsp_off & 0x7ff)<<16);
     return 0;
 }
 
+static int aty_var_to_pll_ct(const struct fb_info_aty *info,
+			     const struct fb_var_screeninfo *var,
+			     struct pll_ct *pll)
+{
+    u32 vclk_per, q, x;		/* x is a workaround for sparc64-linux-gcc */
+    u8 pll_ref_div, pll_gen_cntl, pll_ext_cntl;
+    u8 mclk_fb_div, mclk_post_div, mpostdiv = 0;
+    u8 vclk_fb_div, vclk_post_div, vpostdiv = 0;
+    int err;
 
-static int decode_var(struct fb_var_screeninfo *var,
-		      struct atyfb_par *par, struct fb_info_aty *info)
-{
-    int xres = var->xres;
-    int yres = var->yres;
-    int bpp = var->bits_per_pixel;
-    struct aty_regvals *init;
-
-    /* This should support more video modes */
-
-    if (xres <= 512 && yres <= 384)
-	par->hw.gx.vmode = VMODE_512_384_60;	/* 512x384, 60Hz */
-    else if (xres <= 640 && yres <= 480)
-	par->hw.gx.vmode = VMODE_640_480_67;	/* 640x480, 67Hz */
-    else if (xres <= 640 && yres <= 870)
-	par->hw.gx.vmode = VMODE_640_870_75P;	/* 640x870, 75Hz (portrait) */
-    else if (xres <= 768 && yres <= 576)
-	par->hw.gx.vmode = VMODE_768_576_50I;	/* 768x576, 50Hz (PAL full frame) */
-    else if (xres <= 800 && yres <= 600)
-	par->hw.gx.vmode = VMODE_800_600_75;	/* 800x600, 75Hz */
-    else if (xres <= 832 && yres <= 624)
-	par->hw.gx.vmode = VMODE_832_624_75;	/* 832x624, 75Hz */
-    else if (xres <= 1024 && yres <= 768)
-	par->hw.gx.vmode = VMODE_1024_768_75;	/* 1024x768, 75Hz */
-    else if (xres <= 1152 && yres <= 870)
-	par->hw.gx.vmode = VMODE_1152_870_75;	/* 1152x870, 75Hz */
-    else if (xres <= 1280 && yres <= 960)
-	par->hw.gx.vmode = VMODE_1280_960_75;	/* 1280x960, 75Hz */
-    else if (xres <= 1280 && yres <= 1024)
-	par->hw.gx.vmode = VMODE_1280_1024_75;	/* 1280x1024, 75Hz */
-    else
-	return -EINVAL;
+    x = x;			/* x is a workaround for sparc64-linux-gcc */
 
-    xres = vmode_attrs[par->hw.gx.vmode-1].hres;
-    yres = vmode_attrs[par->hw.gx.vmode-1].vres;
+    pll->pll_vclk_cntl = 0x03;	/* VCLK = PLL_VCLK/VCLKx_POST */
 
-    if (var->xres_virtual <= xres)
-	par->vxres = xres;
+    vclk_per = var->pixclock;
+    pll_ref_div = info->pll_per*2*255/ref_clk_per;
+
+    /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
+    q = ref_clk_per*pll_ref_div*4/info->mclk_per;	/* actually 8*q */
+    if (q < 16*8 || q > 255*8)
+	FAIL("mclk out of range");
+    else if (q < 32*8)
+	mclk_post_div = 8;
+    else if (q < 64*8)
+	mclk_post_div = 4;
+    else if (q < 128*8)
+	mclk_post_div = 2;
     else
-	par->vxres = (var->xres_virtual+7) & ~7;
-    if (var->yres_virtual <= yres)
-	par->vyres = yres;
+	mclk_post_div = 1;
+    mclk_fb_div = q*mclk_post_div/8;
+
+    /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
+    q = ref_clk_per*pll_ref_div*4/vclk_per;	/* actually 8*q */
+    if (q < 16*8 || q > 255*8)
+	FAIL("vclk out of range");
+    else if (q < 32*8)
+	vclk_post_div = 8;
+    else if (q < 64*8)
+	vclk_post_div = 4;
+    else if (q < 128*8)
+	vclk_post_div = 2;
     else
-	par->vyres = var->yres_virtual;
+	vclk_post_div = 1;
+    vclk_fb_div = q*vclk_post_div/8;
 
-    par->xoffset = (var->xoffset+7) & ~7;
-    par->yoffset = var->yoffset;
-    if (par->xoffset+xres > par->vxres || par->yoffset+yres > par->vyres)
-	return -EINVAL;
+    if ((err = aty_dsp_gt(info, mclk_fb_div, mclk_post_div, vclk_fb_div,
+			  vclk_post_div, var->bits_per_pixel, pll)))
+	return err;
 
-    if (bpp <= 8)
-	par->hw.gx.cmode = CMODE_8;
-    else if (bpp <= 16)
-	par->hw.gx.cmode = CMODE_16;
-    else if (bpp <= 32)
-	par->hw.gx.cmode = CMODE_32;
+    if ((((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_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) ||
+	 (Gx == VU_CHIP_ID)) && (info->ram_type >= SDRAM))
+	pll_gen_cntl = 0x04;
     else
-	return -EINVAL;
+	pll_gen_cntl = 0x84;
 
-    if (var->accel_flags & FB_ACCELF_TEXT)
-	par->accel = FB_ACCELF_TEXT;
+    switch (mclk_post_div) {
+	case 1:
+	    mpostdiv = 0;
+	    break;
+	case 2:
+	    mpostdiv = 1;
+	    break;
+	case 3:
+	    mpostdiv = 4;
+	    break;
+	case 4:
+	    mpostdiv = 2;
+	    break;
+	case 8:
+	    mpostdiv = 3;
+	    break;
+    }
+    pll_gen_cntl |= mpostdiv<<4;	/* mclk */
+
+    if (Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48))
+	pll_ext_cntl = 0;
     else
-	par->accel = 0;
+    	pll_ext_cntl = mpostdiv;	/* xclk == mclk */
 
-    if (aty_vram_reqd(par) > info->total_vram)
-	return -EINVAL;
+    switch (vclk_post_div) {
+	case 1:
+	    vpostdiv = 0;
+	    break;
+	case 2:
+	    vpostdiv = 1;
+	    break;
+	case 3:
+	    vpostdiv = 0;
+	    pll_ext_cntl |= 0x10;
+	    break;
+	case 4:
+	    vpostdiv = 2;
+	    break;
+	case 6:
+	    vpostdiv = 2;
+	    pll_ext_cntl |= 0x10;
+	    break;
+	case 8:
+	    vpostdiv = 3;
+	    break;
+	case 12:
+	    vpostdiv = 3;
+	    pll_ext_cntl |= 0x10;
+	    break;
+    }
+    vclk_post_div = vpostdiv;
+
+    pll->pll_ref_div = pll_ref_div;
+    pll->pll_gen_cntl = pll_gen_cntl;
+    pll->mclk_fb_div = mclk_fb_div;
+    pll->vclk_post_div = vclk_post_div;
+    pll->vclk_fb_div = vclk_fb_div;
+    pll->pll_ext_cntl = pll_ext_cntl;
+    return 0;
+}
 
-    /* Check if we know about the wanted video mode */
-    init = get_aty_struct(par->hw.gx.vmode, info);
-    if (init == NULL || init->crtc_h_sync_strt_wid[par->hw.gx.cmode] == 0 ||
-	(info->chip_class != CLASS_GT &&
-	 init->crtc_gen_cntl[par->hw.gx.cmode] == 0) ||
-	(info->chip_class == CLASS_GT &&
-	 (aty_ld_le32(CONFIG_STAT0, info) & 7) == 5 &&
-	 init->crtc_gen_cntl[1] == 0))
+static int aty_pll_ct_to_var(const struct pll_ct *pll,
+			     struct fb_var_screeninfo *var)
+{
+    u8 pll_ref_div = pll->pll_ref_div;
+    u8 vclk_fb_div = pll->vclk_fb_div;
+    u8 vclk_post_div = pll->vclk_post_div;
+    u8 pll_ext_cntl = pll->pll_ext_cntl;
+    static u8 vclk_post_div_tab[] = {
+	1, 2, 4, 8,
+	3, 0, 6, 12
+    };
+    u8 vpostdiv = vclk_post_div_tab[((pll_ext_cntl & 0x10) >> 1) |
+				    (vclk_post_div & 3)];
+    if (vpostdiv == 0)
 	return -EINVAL;
+    var->pixclock = pll_ref_div*vpostdiv*ref_clk_per/vclk_fb_div/2;
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void atyfb_set_par(const struct atyfb_par *par,
+			  struct fb_info_aty *info)
+{
+    u32 i;
+
+    info->current_par = *par;
+
+    aty_set_crtc(info, &par->crtc);
+    aty_st_8(CLOCK_CNTL, 0, info);
+    aty_st_8(CLOCK_CNTL, CLOCK_STROBE, info);
+
+    if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
+	switch (info->dac_type) {
+	    case DAC_IBMRGB514:
+		aty_set_dac_514(info, par->crtc.bpp);
+		break;
+	    case DAC_ATI68860_B:
+		/* FIXME */
+		break;
+	}
+	aty_set_pll_gx(info, &par->pll.gx);
+	aty_st_le32(BUS_CNTL, 0x890e20f1, info);
+	aty_st_le32(DAC_CNTL, 0x47052100, info);
+    } else {
+	aty_set_pll_ct(info, &par->pll.ct);
+	i = aty_ld_le32(MEM_CNTL, info) & 0xf30fffff;
+	if (!(Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48)))
+		i |= info->mem_refresh_rate << 20;
+	switch (par->crtc.bpp) {
+	    case 8:
+	    case 24:
+		i |= 0x00000000;
+		break;
+	    case 16:
+		i |= 0x04000000;
+		break;
+	    case 32:
+		i |= 0x08000000;
+		break;
+	}
+	if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
+	    aty_st_le32(DAC_CNTL, 0x87010184, info);
+	    aty_st_le32(BUS_CNTL, 0x680000f9, info);
+	} else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) {
+	    aty_st_le32(DAC_CNTL, 0x87010184, info);
+	    aty_st_le32(BUS_CNTL, 0x680000f9, info);
+	} else {
+	    /* GT */
+	    aty_st_le32(DAC_CNTL, 0x86010102, info);
+	    aty_st_le32(BUS_CNTL, 0x7b23a040, info);
+	    aty_st_le32(EXT_MEM_CNTL, 0x5000001, info);
+	}
+	aty_st_le32(MEM_CNTL, i, info);
+    }
+    aty_st_8(DAC_MASK, 0xff, info);
+
+    /* Initialize the graphics engine */
+    if (par->accel_flags & FB_ACCELF_TEXT)
+	init_engine(par, info);
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+    if (console_fb_info == &info->fb_info) {
+	struct fb_var_screeninfo var;
+	int vmode, cmode;
+	display_info.height = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1;
+	display_info.width = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8;
+	display_info.depth = par->crtc.bpp;
+	display_info.pitch = par->crtc.vxres*par->crtc.bpp/8;
+	atyfb_encode_var(&var, par, info);
+	if (mac_var_to_vmode(&var, &vmode, &cmode))
+	    display_info.mode = 0;
+	else
+	    display_info.mode = vmode;
+	strcpy(display_info.name, atyfb_name);
+	display_info.fb_address = info->frame_buffer_phys;
+	display_info.cmap_adr_address = info->ati_regbase_phys+0xc0;
+	display_info.cmap_data_address = info->ati_regbase_phys+0xc1;
+	display_info.disp_reg_address = info->ati_regbase_phys;
+    }
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+}
+
+static int atyfb_decode_var(const struct fb_var_screeninfo *var,
+			    struct atyfb_par *par,
+			    const struct fb_info_aty *info)
+{
+    int err;
+
+    if ((err = aty_var_to_crtc(info, var, &par->crtc)))
+	return err;
+    if ((Gx == GX_PCI_ID) || (Gx == CX_PCI_ID))
+	switch (info->clk_type) {
+	    case CLK_ATI18818_1:
+		err = aty_var_to_pll_18818(var, &par->pll.gx);
+		break;
+	    case CLK_IBMRGB514:
+		err = aty_var_to_pll_514(var, &par->pll.gx);
+		break;
+	}
+    else
+	err = aty_var_to_pll_ct(info, var, &par->pll.ct);
+    if (err)
+	return err;
+
+    if (var->accel_flags & FB_ACCELF_TEXT)
+	par->accel_flags = FB_ACCELF_TEXT;
+    else
+	par->accel_flags = 0;
 
 #if 0
     if (!fbmon_valid_timings(pixclock, htotal, vtotal, info))
@@ -1489,197 +1747,192 @@
     return 0;
 }
 
-static int encode_var(struct fb_var_screeninfo *var,
-		      const struct atyfb_par *par,
-		      struct fb_info_aty *info)
+static int atyfb_encode_var(struct fb_var_screeninfo *var,
+			    const struct atyfb_par *par,
+			    const struct fb_info_aty *info)
 {
-    int vmode = par->hw.gx.vmode;
-    int cmode = par->hw.gx.cmode;
-    struct aty_regvals *init = get_aty_struct(vmode, info);
-    u_int h_total, h_disp;
-    u_int h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
-    u_int v_total, v_disp;
-    u_int v_sync_strt, v_sync_wid, v_sync_pol;
-    u_int xtalin, vclk = 0;
-    u8 pll_ref_div, vclk_fb_div, vclk_post_div, pll_ext_cntl;
+    int err;
 
     memset(var, 0, sizeof(struct fb_var_screeninfo));
-    if (!init)
-	return -EINVAL;
 
-    var->xres = vmode_attrs[vmode-1].hres;
-    var->yres = vmode_attrs[vmode-1].vres;
-    var->xres_virtual = par->vxres;
-    var->yres_virtual = par->vyres;
-    var->xoffset = par->xoffset;
-    var->yoffset = par->yoffset;
-    var->grayscale = 0;
-    switch (cmode) {
-	case CMODE_8:
-	    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;
-	    break;
-	case CMODE_16:	/* RGB 555 */
-	    var->bits_per_pixel = 16;
-	    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 = 0;
-	    var->transp.length = 0;
-	    break;
-	case CMODE_32:	/* RGB 888 */
-	    var->bits_per_pixel = 32;
-	    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;
-	    break;
-    }
-    var->red.msb_right = 0;
-    var->green.msb_right = 0;
-    var->blue.msb_right = 0;
-    var->transp.msb_right = 0;
-    var->nonstd = 0;
-    var->activate = 0;
+    if ((err = aty_crtc_to_var(&par->crtc, var)))
+	return err;
+    if ((Gx == GX_PCI_ID) || (Gx == CX_PCI_ID))
+	err = aty_pll_gx_to_var(&par->pll.gx, var);
+    else
+	err = aty_pll_ct_to_var(&par->pll.ct, var);
+    if (err)
+	return err;
+
     var->height = -1;
     var->width = -1;
-    var->vmode = FB_VMODE_NONINTERLACED;
-    var->accel_flags = par->accel;
+    var->accel_flags = par->accel_flags;
+
+    return 0;
+}
+
+
+
+static void set_off_pitch(struct atyfb_par *par,
+			  const struct fb_info_aty *info)
+{
+    u32 xoffset = par->crtc.xoffset;
+    u32 yoffset = par->crtc.yoffset;
+    u32 vxres = par->crtc.vxres;
+    u32 bpp = par->crtc.bpp;
+
+    par->crtc.off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
+    aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, info);
+}
+
+
+    /*
+     *  Open/Release the frame buffer device
+     */
+
+static int atyfb_open(struct fb_info *info, int user)
 
-    h_total = (init->crtc_h_tot_disp<<3) & 0xff8;
-    h_disp = (init->crtc_h_tot_disp>>13) & 0x7f8;
-    h_sync_strt = ((init->crtc_h_sync_strt_wid[cmode]<<3) & 0x7f8) |
-		  ((init->crtc_h_sync_strt_wid[cmode]>>1) & 0x800);
-    h_sync_dly = (init->crtc_h_sync_strt_wid[cmode]>>8) & 0x7;
-    h_sync_wid = (init->crtc_h_sync_strt_wid[cmode]>>13) & 0xf8;
-    h_sync_pol = (init->crtc_h_sync_strt_wid[cmode]>>21) & 0x1;
-
-    v_total = init->crtc_v_tot_disp & 0x7ff;
-    v_disp = (init->crtc_v_tot_disp>>16) & 0x7ff;
-    v_sync_strt = init->crtc_v_sync_strt_wid & 0x7ff;
-    v_sync_wid = (init->crtc_v_sync_strt_wid>>16) & 0x1f;
-    v_sync_pol = (init->crtc_v_sync_strt_wid>>21) & 0x1;
-
-    var->left_margin = (h_total+8)-h_sync_strt-h_sync_wid;
-    var->right_margin = h_sync_strt-(h_disp+8);
-    var->upper_margin = (v_total+1)-v_sync_strt-v_sync_wid;
-    var->lower_margin = v_sync_strt-(v_disp+1);
-    var->hsync_len = h_sync_wid;
-    var->vsync_len = v_sync_wid;
-    var->sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
-		(v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT);
-
-    xtalin = 69841;	/* 14.31818 MHz */
-    switch (info->chip_class) {
-	case CLASS_GX:
-	    {
-		/* haven't read the IBM RGB514 PDF yet, so just guesses */
-		static u32 gx_vclk[VMODE_MAX] = {
-		        0,	/* vmode  1 */	
-		        0,	/* vmode  2 */	
-		        0,	/* vmode  3 */	
-		        0,	/* vmode  4 */	
-		    39722,	/* vmode  5 (25.175 MHz) */
-		    33333,	/* vmode  6 (30 MHz) */
-		        0,	/* vmode  7 */	
-		        0,	/* vmode  8 */	
-		    27778,	/* vmode  9 (36 MHz) */
-		    25000,	/* vmode 10 (40 MHz) */
-		    20000,	/* vmode 11 (50 MHz) */
-		    20000,	/* vmode 12 (50 MHz) */
-		    17544,	/* vmode 13 (57 MHz) */
-		    15385,	/* vmode 14 (65 MHz) */
-		    13333,	/* vmode 15 (75 MHz) */
-		        0,	/* vmode 16 */	
-		    12821,	/* vmode 17 (78 MHz) */
-		    10000,	/* vmode 18 (100 MHz) */
-		     7937,	/* vmode 19 (126 MHz) */
-		     7407	/* vmode 20 (135 MHz) */
-		};
-		vclk = gx_vclk[vmode-1];
-	    }
-	    break;
-	case CLASS_CT:
-	case CLASS_GT:
-	case CLASS_VT:
-	    if (info->chip_class == CLASS_GT) {
-		pll_ref_div = 0x21;
-		vclk_post_div = init->offset[0];
-		vclk_fb_div = init->offset[1];
-		pll_ext_cntl = init->offset[2];
-	    } else {
-		pll_ref_div = 0x2d;
-		vclk_post_div = init->clock_val[0];
-		vclk_fb_div = init->clock_val[1];
-		pll_ext_cntl = 0x0;
-	    }
-	    vclk = xtalin*pll_ref_div;
-	    switch (vclk_post_div & 3) {
-		case 0:
-		    vclk *= (pll_ext_cntl & 0x10) ? 3 : 1;
-		    break;
-		case 1:
-		    if (pll_ext_cntl & 0x10)
-			return -EINVAL;
-		    vclk *= 2;
-		    break;
-		case 2:
-		    vclk *= (pll_ext_cntl & 0x10) ? 6 : 4;
-		    break;
-		case 3:
-		    vclk *= (pll_ext_cntl & 0x10) ? 12 : 8;
-		    break;
-	    }
-	    vclk /= 2*vclk_fb_div;
-	    break;
+{
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)info;
+
+    if (user) {
+	if (fb->open)
+	    return -EBUSY;
+	fb->mmaped = 0;
+	fb->open = 1;
+	fb->vtconsole = -1;
+    } else {
+	fb->consolecnt++;
     }
-    var->pixclock = vclk;
+#endif
+    MOD_INC_USE_COUNT;
+    return(0);
+}
 
-    return 0;
+static int atyfb_release(struct fb_info *info, int user)
+{
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)info;
+
+    if (user) {
+	if (fb->vtconsole != -1)
+	    vt_cons[fb->vtconsole]->vc_mode = KD_TEXT;
+	fb->open = 0;
+	fb->mmaped = 0;
+	fb->vtconsole = -1;
+    } else {
+	fb->consolecnt--;
+    }
+#endif
+    MOD_DEC_USE_COUNT;
+    return(0);
 }
 
 
-static void init_par(struct atyfb_par *par, int vmode, int cmode)
+static int encode_fix(struct fb_fix_screeninfo *fix,
+		      const struct atyfb_par *par,
+		      const struct fb_info_aty *info)
 {
-    par->hw.gx.vmode = vmode;
-    par->hw.gx.cmode = cmode;
-    par->vxres = vmode_attrs[vmode-1].hres;
-    par->vyres = vmode_attrs[vmode-1].vres;
-    par->xoffset = 0;
-    par->yoffset = 0;
-    par->accel = FB_ACCELF_TEXT;
+    memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+    strcpy(fix->id, atyfb_name);
+    fix->smem_start = (char *)info->frame_buffer_phys;
+    fix->smem_len = (u32)info->total_vram;
+
+#ifdef __LITTLE_ENDIAN
+    /*
+     *  Last page of 8 MB little-endian aperture is MMIO
+     *  FIXME: we should use the auxiliary aperture instead so we can acces the
+     *  full 8 MB of video RAM on 8 MB boards
+     */
+    if (fix->smem_len > 0x800000-GUI_RESERVE)
+	fix->smem_len = 0x800000-GUI_RESERVE;
+#endif
+    /*
+     *  Reg Block 0 (CT-compatible block) is at ati_regbase_phys
+     *  Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400
+     */
+    if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
+	fix->mmio_start = (char *)info->ati_regbase_phys;
+	fix->mmio_len = 0x400;
+	fix->accel = FB_ACCEL_ATI_MACH64GX;
+    } else if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
+	fix->mmio_start = (char *)info->ati_regbase_phys;
+	fix->mmio_len = 0x400;
+	fix->accel = FB_ACCEL_ATI_MACH64CT;
+    } else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) {
+	fix->mmio_start = (char *)(info->ati_regbase_phys-0x400);
+	fix->mmio_len = 0x800;
+	fix->accel = FB_ACCEL_ATI_MACH64VT;
+    } else {
+	fix->mmio_start = (char *)(info->ati_regbase_phys-0x400);
+	fix->mmio_len = 0x800;
+	fix->accel = FB_ACCEL_ATI_MACH64GT;
+    }
+    fix->type = FB_TYPE_PACKED_PIXELS;
+    fix->type_aux = 0;
+    fix->line_length = par->crtc.vxres*par->crtc.bpp/8;
+    fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR
+				     : FB_VISUAL_DIRECTCOLOR;
+    fix->ywrapstep = 0;
+    fix->xpanstep = 8;
+    fix->ypanstep = 1;
+
+    return 0;
 }
 
 
+struct fb_var_screeninfo default_var = {
+    /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+    640, 480, 640, 480, 0, 0, 8, 0,
+    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
+    0, FB_VMODE_NONINTERLACED
+};
+
+#ifdef __sparc__
+struct fb_var_screeninfo default_var_1024x768 __initdata = {
+    /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
+    1024, 768, 1024, 768, 0, 0, 8, 0,
+    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0, 12699, 176, 16, 28, 1, 96, 3,
+    FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+
+struct fb_var_screeninfo default_var_1152x900 __initdata = {
+    /* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */
+    1152, 900, 1152, 900, 0, 0, 8, 0,
+    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0, 9091, 234, 24, 34, 3, 100, 3,
+    FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+
+struct fb_var_screeninfo default_var_1280x1024 __initdata = {
+    /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
+    1280, 1024, 1280, 1024, 0, 0, 8, 0,
+    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0, 7408, 248, 16, 38, 1, 144, 3,
+    FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+#endif
+
+
     /*
      *  Get the Fixed Part of the Display
      */
 
 static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info)
+			 struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    const struct fb_info_aty *info = (struct fb_info_aty *)fb;
     struct atyfb_par par;
 
     if (con == -1)
-	par = info2->default_par;
+	par = info->default_par;
     else
-	decode_var(&fb_display[con].var, &par, info2);
-    encode_fix(fix, &par, info2);
+	atyfb_decode_var(&fb_display[con].var, &par, info);
+    encode_fix(fix, &par, info);
     return 0;
 }
 
@@ -1689,12 +1942,12 @@
      */
 
 static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
+			 struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    const struct fb_info_aty *info = (struct fb_info_aty *)fb;
 
     if (con == -1)
-	encode_var(var, &info2->default_par, (struct fb_info_aty *)info);
+	atyfb_encode_var(var, &info->default_par, info);
     else
 	*var = fb_display[con].var;
     return 0;
@@ -1706,9 +1959,9 @@
      */
 
 static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
+			 struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
     struct atyfb_par par;
     struct display *display;
     int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err;
@@ -1717,12 +1970,12 @@
     if (con >= 0)
 	display = &fb_display[con];
     else
-	display = &fb_disp;	/* used during initialization */
+	display = fb->disp;	/* used during initialization */
 
-    if ((err = decode_var(var, &par, info2)))
+    if ((err = atyfb_decode_var(var, &par, info)))
 	return err;
 
-    encode_var(var, &par, (struct fb_info_aty *)info);
+    atyfb_encode_var(var, &par, (struct fb_info_aty *)info);
 
     if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
 	oldxres = display->var.xres;
@@ -1737,8 +1990,8 @@
 	    oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) {
 	    struct fb_fix_screeninfo fix;
 
-	    encode_fix(&fix, &par, info2);
-	    display->screen_base = (char *)info2->frame_buffer;
+	    encode_fix(&fix, &par, info);
+	    display->screen_base = (char *)info->frame_buffer;
 	    display->visual = fix.visual;
 	    display->type = fix.type;
 	    display->type_aux = fix.type_aux;
@@ -1748,20 +2001,25 @@
 	    display->can_soft_blank = 1;
 	    display->inverse = 0;
 	    accel = var->accel_flags & FB_ACCELF_TEXT;
-	    switch (par.hw.gx.cmode) {
+	    switch (par.crtc.bpp) {
 #ifdef FBCON_HAS_CFB8
-		case CMODE_8:
-		    display->dispsw = accel ? &fbcon_aty8 : &fbcon_cfb8;
+		case 8:
+		    *display->dispsw = accel ? fbcon_aty8 : fbcon_cfb8;
 		    break;
 #endif
 #ifdef FBCON_HAS_CFB16
-		case CMODE_16:
-		    display->dispsw = accel ? &fbcon_aty16 : &fbcon_cfb16;
+		case 16:
+		    *display->dispsw = accel ? fbcon_aty16 : fbcon_cfb16;
+		    break;
+#endif
+#ifdef FBCON_HAS_CFB24
+		case 24:
+		    *display->dispsw = accel ? fbcon_aty24 : fbcon_cfb24;
 		    break;
 #endif
 #ifdef FBCON_HAS_CFB32
-		case CMODE_32:
-		    display->dispsw = accel ? &fbcon_aty32 : &fbcon_cfb32;
+		case 32:
+		    *display->dispsw = accel ? fbcon_aty32 : fbcon_cfb32;
 		    break;
 #endif
 		default:
@@ -1769,19 +2027,19 @@
 		    break;
 	    }
 	    display->scrollmode = accel ? 0 : SCROLL_YREDRAW;
-	    if (info->changevar)
-		(*info->changevar)(con);
-	    if (info2->cursor) {
-	    	display->dispsw->cursor = atyfb_cursor;
-	    	display->dispsw->set_font = atyfb_set_font;
+	    if (info->fb_info.changevar)
+		(*info->fb_info.changevar)(con);
+	    if (info->cursor) {
+		display->dispsw->cursor = atyfb_cursor;
+		display->dispsw->set_font = atyfb_set_font;
 	    }
 	}
 	if (con == currcon)
-	    atyfb_set_par(&par, info2);
+	    atyfb_set_par(&par, info);
 	if (oldbpp != var->bits_per_pixel) {
 	    if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
 		return err;
-	    do_install_cmap(con, info);
+	    do_install_cmap(con, &info->fb_info);
 	}
     }
 
@@ -1796,21 +2054,21 @@
      */
 
 static int atyfb_pan_display(struct fb_var_screeninfo *var, int con,
-			     struct fb_info *info)
+			     struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
     u32 xres, yres, xoffset, yoffset;
-    struct atyfb_par *par = &info2->current_par;
+    struct atyfb_par *par = &info->current_par;
 
-    xres = vmode_attrs[par->hw.gx.vmode-1].hres;
-    yres = vmode_attrs[par->hw.gx.vmode-1].vres;
+    xres = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8;
+    yres = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1;
     xoffset = (var->xoffset+7) & ~7;
     yoffset = var->yoffset;
-    if (xoffset+xres > par->vxres || yoffset+yres > par->vyres)
+    if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres)
 	return -EINVAL;
-    par->xoffset = xoffset;
-    par->yoffset = yoffset;
-    set_off_pitch(par, info2);
+    par->crtc.xoffset = xoffset;
+    par->crtc.yoffset = yoffset;
+    set_off_pitch(par, info);
     return 0;
 }
 
@@ -1965,6 +2223,18 @@
 	vma->vm_file = file;
 	file->f_count++;
 	vma->vm_flags |= VM_IO;
+
+	if (!fb->mmaped) {
+		int lastconsole = 0;
+
+		if (info->display_fg)
+			lastconsole = info->display_fg->vc_num;
+		fb->mmaped = 1;
+		if (fb->consolecnt && fb_display[lastconsole].fb_info == info) {
+			fb->vtconsole = lastconsole;
+			vt_cons[lastconsole]->vc_mode = KD_GRAPHICS;
+		}
+	}
 	return 0;
 }
 #endif /* __sparc__ */
@@ -1977,179 +2247,206 @@
 {
     u32 chip_id;
     u32 i;
-    int j, k, sense;
+    int j, k;
     struct fb_var_screeninfo var;
-    struct aty_regvals *init;
+    struct display *disp;
     const char *chipname = NULL;
-    u8 rev;
+    int pll, mclk;
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+    int sense;
+#endif
 
     info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0);
     chip_id = aty_ld_le32(CONFIG_CHIP_ID, info);
+    Gx = chip_id & CFG_CHIP_TYPE;
+    Rev = (chip_id & CFG_CHIP_REV)>>24;
     for (j = 0; j < (sizeof(aty_features)/sizeof(*aty_features)); j++)
-	if (aty_features[j].chip_type == (chip_id & CFG_CHIP_TYPE)) {
+	if (aty_features[j].chip_type == Gx) {
 	    chipname = aty_features[j].name;
-	    info->chip_class = aty_features[j].chip_class;
-	    info->pixclock_lim_8 = 1000000/aty_features[j].pixclock_lim_8;
-	    info->pixclock_lim_hi = 1000000/aty_features[j].pixclock_lim_hi;
+	    break;
 	}
     if (!chipname) {
-	printk("atyfb: Unknown Mach64 0x%04x\n", chip_id & CFG_CHIP_TYPE);
+	printk("atyfb: Unknown mach64 0x%04x\n", Gx);
 	return 0;
     } else
-	printk("atyfb: %s [", chipname);
-    rev = (chip_id & CFG_CHIP_REV)>>24;
-    switch ((rev>>3) & 7) {
-	case MACH64_FND_SGS:
-	    printk("SGS");
-	    break;
-	case MACH64_FND_NEC:
-	    printk("NEC");
-	    break;
-	case MACH64_FND_UMC:
-	    printk("UMC");
-	    break;
+	printk("atyfb: %s [0x%04x rev 0x%2x] ", chipname, Gx, Rev);
+    if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
+	info->bus_type = (aty_ld_le32(CONFIG_STAT0, info) >> 0) & 0x07;
+	info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) >> 3) & 0x07;
+	/* FIXME: clockchip/RAMDAC probing? */
+#ifdef CONFIG_ATARI
+	info->dac_type = DAC_ATI68860_B;
+	info->clk_type = CLK_ATI18818_1;
+#else
+	info->dac_type = DAC_IBMRGB514;
+	info->clk_type = CLK_IBMRGB514;
+#endif
+	/* FIXME */
+	pll = 135;
+	mclk = 50;
+    } else {
+	info->bus_type = PCI;
+	info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07);
+	info->dac_type = DAC_INTERNAL;
+	info->clk_type = CLK_INTERNAL;
+	if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
+	    pll = 135;
+	    mclk = 60;
+	} else {
+	    mclk = info->ram_type >= SDRAM ? 67 : 63;
+	    if ((Gx == VT_CHIP_ID) && (Rev == 0x08)) {
+		/* VTA3 */
+		pll = 170;
+	    } else if (((Gx == VT_CHIP_ID) && ((Rev == 0x40) ||
+					       (Rev == 0x48))) ||
+		       ((Gx == VT_CHIP_ID) && ((Rev == 0x01) ||
+					       (Rev == 0x9a))) ||
+		       (Gx == VU_CHIP_ID)) {
+		/* VTA4 or VTB */
+		pll = 200;
+	    } else if (Gx == VT_CHIP_ID) {
+		/* other VT */
+		pll = 135;
+		mclk = 63;
+	    } else if ((Gx == GT_CHIP_ID) && (Rev & 0x01)) {
+		/* RAGE II */
+		pll = 170;
+	    } else if (((Gx == GT_CHIP_ID) && (Rev & 0x02)) ||
+		       (Gx == GU_CHIP_ID)) {
+		/* RAGE II+ */
+		pll = 200;
+	    } else if ((Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
+		       (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) ||
+		       (Gx == GQ_CHIP_ID)) {
+		/* RAGE PRO */
+		pll = 230;
+	    } else {
+		/* other RAGE */
+		pll = 135;
+		mclk = 63;
+	    }
+	}
     }
-    printk(" %c%d]\n", 'A'+(rev & 7), rev>>6);
+    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 */
+    printk("%d MHz PLL, %d Mhz MCLK\n", pll, mclk);
+    info->pll_per = 1000000/pll;
+    info->mclk_per = 1000000/mclk;
 
     i = aty_ld_le32(MEM_CNTL, info);
-    if (info->chip_class != CLASS_GT)
-	switch (i & MEM_SIZE_ALIAS) {
+    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))
+	switch (i & 0xF) {	/* 0xF used instead of MEM_SIZE_ALIAS */
 	    case MEM_SIZE_512K:
 		info->total_vram = 0x80000;
 		break;
 	    case MEM_SIZE_1M:
 		info->total_vram = 0x100000;
 		break;
-	    case MEM_SIZE_2M:
+	    case MEM_SIZE_2M_GTB:
 		info->total_vram = 0x200000;
 		break;
-	    case MEM_SIZE_4M:
+	    case MEM_SIZE_4M_GTB:
 		info->total_vram = 0x400000;
 		break;
-	    case MEM_SIZE_6M:
+	    case MEM_SIZE_6M_GTB:
 		info->total_vram = 0x600000;
 		break;
-	    case MEM_SIZE_8M:
+	    case MEM_SIZE_8M_GTB:
 		info->total_vram = 0x800000;
 		break;
 	    default:
 		info->total_vram = 0x80000;
 	}
     else
-	switch (i & 0xF) {	/* 0xF used instead of MEM_SIZE_ALIAS */
+	switch (i & MEM_SIZE_ALIAS) {
 	    case MEM_SIZE_512K:
 		info->total_vram = 0x80000;
 		break;
 	    case MEM_SIZE_1M:
 		info->total_vram = 0x100000;
 		break;
-	    case MEM_SIZE_2M_GTB:
+	    case MEM_SIZE_2M:
 		info->total_vram = 0x200000;
 		break;
-	    case MEM_SIZE_4M_GTB:
+	    case MEM_SIZE_4M:
 		info->total_vram = 0x400000;
 		break;
-	    case MEM_SIZE_6M_GTB:
+	    case MEM_SIZE_6M:
 		info->total_vram = 0x600000;
 		break;
-	    case MEM_SIZE_8M_GTB:
+	    case MEM_SIZE_8M:
 		info->total_vram = 0x800000;
 		break;
 	    default:
 		info->total_vram = 0x80000;
 	}
-#ifdef CONFIG_ATARI	/* this is definately not the wrong way to set this */
-    if ((info->total_vram == 0x400000) || (info->total_vram == 0x800000)) {
-	/* protect GUI-regs if complete Aperture is VRAM */
-	info->total_vram -= 0x00001000;
-    }
-#endif
 
-#if 0
-    printk("aty_init: regbase = %lx, frame_buffer = %lx, total_vram = %x\n",
-	   info->ati_regbase, info->frame_buffer, info->total_vram);
-#endif
+    if (info->bus_type == ISA)
+	if ((info->total_vram == 0x400000) || (info->total_vram == 0x800000)) {
+	    /* protect GUI-regs if complete Aperture is VRAM */
+	    info->total_vram -= GUI_RESERVE;
+	}
 
-    sense = read_aty_sense(info);
-#if 0
-    printk("monitor sense = %x\n", sense);
-#endif
 #if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
     if (default_vmode == VMODE_NVRAM) {
 	default_vmode = nvram_read_byte(NV_VMODE);
-	init = get_aty_struct(default_vmode, info);
-	if (default_vmode <= 0 || default_vmode > VMODE_MAX || init == 0)
+	if (default_vmode <= 0 || default_vmode > VMODE_MAX)
 	    default_vmode = VMODE_CHOOSE;
     }
-    if (default_vmode == VMODE_CHOOSE)
-	default_vmode = map_monitor_sense(sense);
-#else /* !CONFIG_PMAC && !CONFIG_CHRP */
-    if (default_vmode == VMODE_NVRAM)
-	default_vmode = map_monitor_sense(sense);
-#endif /* !CONFIG_PMAC && !CONFIG_CHRP */
-
-    if (!(init = get_aty_struct(default_vmode, info)))
+    if (default_vmode == VMODE_CHOOSE) {
+	sense = read_aty_sense(info);
+	default_vmode = mac_map_monitor_sense(sense);
+    }
+    if (default_vmode <= 0 || default_vmode > VMODE_MAX)
 	default_vmode = VMODE_640_480_60;
-
-    /*
-     * Reduce the pixel size if we don't have enough VRAM.
-     */
-
     if (default_cmode == CMODE_NVRAM)
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
 	default_cmode = nvram_read_byte(NV_CMODE);
-#else /* !CONFIG_PMAC && !CONFIG_CHRP */
-	default_cmode = CMODE_8;
-#endif /* !CONFIG_PMAC && !CONFIG_CHRP */
     if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
 	default_cmode = CMODE_8;
-
-    init_par(&info->default_par, default_vmode, default_cmode);
-    while (aty_vram_reqd(&info->default_par) > info->total_vram) {
-	while (default_cmode > CMODE_8 &&
-	       aty_vram_reqd(&info->default_par) > info->total_vram) {
-	    --default_cmode;
-	    init_par(&info->default_par, default_vmode, default_cmode);
-	}
-	/*
-	 * Adjust the video mode smaller if there still is not enough VRAM
-	 */
-	if (aty_vram_reqd(&info->default_par) > info->total_vram)
-	    do {
-		default_vmode--;
-		init_par(&info->default_par, default_vmode, default_cmode);
-		init = get_aty_struct(default_vmode, info);
-	    } while ((init == 0) &&
-		     (default_vmode > VMODE_640_480_60));
-    }
-
-    if (info->chip_class == CLASS_GT &&
-	(aty_ld_le32(CONFIG_STAT0, info) & 7) == 5
-	&& init->crtc_gen_cntl[1] == 0) {
-	    default_vmode = VMODE_640_480_67;
-	    default_cmode = CMODE_8;
-	    init_par(&info->default_par, default_vmode, default_cmode);
-    }
-
-    switch (info->chip_class) {
-	case CLASS_GX:
-	    strcat(atyfb_name, "GX");
-	    break;
-	case CLASS_CT:
-	    strcat(atyfb_name, "CT");
-	    break;
-	case CLASS_VT:
-	    strcat(atyfb_name, "VT");
-	    break;
-	case CLASS_GT:
-	    strcat(atyfb_name, "GT");
-	    break;
+    if (mac_vmode_to_var(default_vmode, default_cmode, &var))
+	var = default_var;
+#else /* !CONFIG_PMAC && !CONFIG_CHRP */
+    var = default_var;
+#endif /* !CONFIG_PMAC && !CONFIG_CHRP */
+    var.accel_flags |= FB_ACCELF_TEXT;
+    if (atyfb_decode_var(&var, &info->default_par, info)) {
+	printk("atyfb: can't set default video mode\n");
+	return 0;
     }
+
+    if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))
+	strcat(atyfb_name, "GX");
+    else if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID))
+	strcat(atyfb_name, "CT");
+    else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID))
+	strcat(atyfb_name, "VT");
+    else
+	strcat(atyfb_name, "GT");
+
+    disp = &info->disp;
+
     strcpy(info->fb_info.modename, atyfb_name);
     info->fb_info.node = -1;
     info->fb_info.fbops = &atyfb_ops;
-    info->fb_info.disp = &fb_disp;
-    info->fb_info.fontname[0] = '\0';
+    info->fb_info.disp = disp;
+    strcpy(info->fb_info.fontname, fontname);
     info->fb_info.changevar = NULL;
     info->fb_info.switch_con = &atyfbcon_switch;
     info->fb_info.updatevar = &atyfbcon_updatevar;
@@ -2162,13 +2459,16 @@
 	info->palette[j].blue = default_blu[k];
     }
 
-    if (info->chip_class == CLASS_VT || info->chip_class == CLASS_GT) {
+    if ((Gx == VT_CHIP_ID) || (Gx == GT_CHIP_ID) || (Gx == GU_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) ||
+	(Gx == VU_CHIP_ID)) {
 	info->cursor = kmalloc(sizeof(struct aty_cursor), GFP_ATOMIC);
-	memset(info->cursor, 0, sizeof(*info->cursor));
+	if (info->cursor)
+	    memset(info->cursor, 0, sizeof(*info->cursor));
     }
 
-    atyfb_set_par(&info->default_par, info);
-    encode_var(&var, &info->default_par, info);
+    disp->dispsw = &info->dispsw;
     atyfb_set_var(&var, -1, &info->fb_info);
 
     if (register_framebuffer(&info->fb_info) < 0)
@@ -2188,14 +2488,16 @@
     struct pci_dev *pdev;
     struct fb_info_aty *info;
     unsigned long addr;
-    int i, j;
-    u16 tmp;
 #ifdef __sparc__
     extern int con_is_present(void);
+    u32 chip_id;
+    int i, j;
 
     /* Do not attach when we have a serial console. */
     if (!con_is_present())
-	    return;
+	return;
+#else
+    u16 tmp;
 #endif
 
     for (pdev = pci_devices; pdev; pdev = pdev->next) {
@@ -2236,7 +2538,7 @@
 		/* nothing */;
 	    j = i + 1;
 
-            info->mmap_map = kmalloc(j * sizeof(*info->mmap_map), GFP_ATOMIC);
+	    info->mmap_map = kmalloc(j * sizeof(*info->mmap_map), GFP_ATOMIC);
 	    if (!info->mmap_map) {
 		printk("atyfb_init: can't alloc mmap_map\n");
 		kfree(info);
@@ -2284,8 +2586,8 @@
 	    /*
 	     * Fix PROMs idea of MEM_CNTL settings...
 	     */
-	    tmp = aty_ld_le32(CONFIG_CHIP_ID, info) & CFG_CHIP_TYPE;
-	    if (tmp == VT_CHIP_ID) {
+	    chip_id = aty_ld_le32(CONFIG_CHIP_ID, info) & CFG_CHIP_TYPE;
+	    if ((chip_id & 0xffff) == VT_CHIP_ID && !((chip_id >> 24) & 1)) {
 		u32 mem = aty_ld_le32(MEM_CNTL, info);
 		switch (mem & 0x0f) {
 		    case 3:
@@ -2318,34 +2620,35 @@
 		int height = prom_getintdefault(node, "height", 768);
 		int depth = prom_getintdefault(node, "depth", 8);
 
-		switch (depth) {
-		    case 8:
-			default_cmode = CMODE_8;
+		switch (width) {
+		    case 1024:
+			if (height == 768)
+			    default_var = default_var_1024x768;
 			break;
-		    case 16:
-			default_cmode = CMODE_16;
+		    case 1152:
+			if (height == 900)
+			    default_var = default_var_1152x900;
 			break;
-		    case 32:
-			default_cmode = CMODE_32;
+		    case 1280:
+			if (height == 1024)
+			    default_var = default_var_1280x1024;
 			break;
 		    default:
 			break;
 		}
 
-		switch (width) {
-		    case 1024:
-			if (height == 768)
-			    default_vmode = VMODE_1024_768_75;
+		switch (depth) {
+		    case 8:
+			default_var.bits_per_pixel = 8;
 			break;
-		    case 1152:
-			if (height == 870)
-			    default_vmode = VMODE_1152_870_75;
+		    case 16:
+			default_var.bits_per_pixel = 16;
 			break;
-		    case 1280:
-			if (height == 960)
-			    default_vmode = VMODE_1280_960_75;
-			else if (height == 1024)
-			    default_vmode = VMODE_1280_1024_75;
+		    case 24:
+			default_var.bits_per_pixel = 24;
+			break;
+		    case 32:
+			default_var.bits_per_pixel = 32;
 			break;
 		    default:
 			break;
@@ -2354,9 +2657,6 @@
 
 #else /* __sparc__ */
 
-	    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, 0x1000);
@@ -2388,7 +2688,7 @@
 	    if (!aty_init(info, "PCI")) {
 		if (info->mmap_map)
 		    kfree(info->mmap_map);
-	        kfree(info);
+		kfree(info);
 	    }
 	}
     }
@@ -2500,39 +2800,51 @@
 __initfunc(void atyfb_setup(char *options, int *ints))
 {
     char *this_opt;
-    int vmode;
-    int depth;
+
     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 defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
 	if (!strncmp(this_opt, "vmode:", 6)) {
-	    vmode = simple_strtoul(this_opt+6, NULL, 0);
+	    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)) {
-	    depth = simple_strtoul(this_opt+6, NULL, 0);
+	    int depth = simple_strtoul(this_opt+6, NULL, 0);
 	    switch (depth) {
 		case 8:
-		    default_cmode = CMODE_8;
+		    default_cmode = 0;
 		    break;
 		case 15:
 		case 16:
-		    default_cmode = CMODE_16;
+		    default_cmode = 1;
 		    break;
 		case 24:
 		case 32:
-		    default_cmode = CMODE_32;
+		    default_cmode = 2;
 		    break;
 	    }
 	}
+#endif
 #ifdef CONFIG_ATARI
 	/*
 	 * Why do we need this silly Mach64 argument?
 	 * We are already here because of mach64= so its redundant.
 	 */
-	else if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) {
+	if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) {
 	    static unsigned char m64_num;
 	    static char mach64_str[80];
 	    strncpy(mach64_str, this_opt+7, 80);
@@ -2595,39 +2907,48 @@
 }
 #endif /* CONFIG_ATARI */
 
-static int atyfbcon_switch(int con, struct fb_info *info)
+static int atyfbcon_switch(int con, struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
     struct atyfb_par par;
 
     /* Do we have to save the colormap? */
     if (fb_display[currcon].cmap.len)
 	fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1,
-		    atyfb_getcolreg, info);
+		    atyfb_getcolreg, fb);
+
+    /* Erase HW Cursor */
+    if (info->cursor)
+	atyfb_cursor(&fb_display[currcon], CM_ERASE,
+		     info->cursor->pos.x, info->cursor->pos.y);
+
     currcon = con;
-    decode_var(&fb_display[con].var, &par, info2);
-    atyfb_set_par(&par, info2);
+
+    atyfb_decode_var(&fb_display[con].var, &par, info);
+    atyfb_set_par(&par, info);
+
     /* Install new colormap */
-    do_install_cmap(con, info);
+    do_install_cmap(con, fb);
+
     /* Install hw cursor */
-    if (info2->cursor) {
-	aty_set_cursor_color(info2, cursor_pixel_map, cursor_color_map,
+    if (info->cursor) {
+	aty_set_cursor_color(info, cursor_pixel_map, cursor_color_map,
 			     cursor_color_map, cursor_color_map);
-	aty_set_cursor_shape(info2);
+	aty_set_cursor_shape(info);
     }
-    return 0;
+    return 1;
 }
 
     /*
      *  Update the `var' structure (called by fbcon.c)
      */
 
-static int atyfbcon_updatevar(int con, struct fb_info *info)
+static int atyfbcon_updatevar(int con, struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
 
-    info2->current_par.yoffset = fb_display[con].var.yoffset;
-    set_off_pitch(&info2->current_par, info2);
+    info->current_par.crtc.yoffset = fb_display[con].var.yoffset;
+    set_off_pitch(&info->current_par, info);
     return 0;
 }
 
@@ -2635,12 +2956,12 @@
      *  Blank the display.
      */
 
-static void atyfbcon_blank(int blank, struct fb_info *info)
+static void atyfbcon_blank(int blank, struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
     u8 gen_cntl;
 
-    gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info2);
+    gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info);
     if (blank > 0)
 	switch (blank-1) {
 	    case VESA_NO_BLANKING:
@@ -2658,7 +2979,7 @@
 	}
     else
 	gen_cntl &= ~(0x4c);
-    aty_st_8(CRTC_GEN_CNTL, gen_cntl, info2);
+    aty_st_8(CRTC_GEN_CNTL, gen_cntl, info);
 }
 
 
@@ -2668,15 +2989,15 @@
      */
 
 static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-			   u_int *transp, struct fb_info *info)
+			   u_int *transp, struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
 
     if (regno > 255)
 	return 1;
-    *red = info2->palette[regno].red;
-    *green = info2->palette[regno].green;
-    *blue = info2->palette[regno].blue;
+    *red = info->palette[regno].red;
+    *green = info->palette[regno].green;
+    *blue = info->palette[regno].blue;
     return 0;
 }
 
@@ -2688,36 +3009,41 @@
      */
 
 static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-			   u_int transp, struct fb_info *info)
+			   u_int transp, struct fb_info *fb)
 {
-    struct fb_info_aty *info2 = (struct fb_info_aty *)info;
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
     int i, scale;
 
     if (regno > 255)
 	return 1;
-    info2->palette[regno].red = red;
-    info2->palette[regno].green = green;
-    info2->palette[regno].blue = blue;
-    i = aty_ld_8(DAC_CNTL, info2) & 0xfc;
-    if (info2->chip_class == CLASS_GT)
+    info->palette[regno].red = red;
+    info->palette[regno].green = green;
+    info->palette[regno].blue = blue;
+    i = aty_ld_8(DAC_CNTL, info) & 0xfc;
+    if ((Gx == GT_CHIP_ID) || (Gx == GU_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))
 	i |= 0x2;	/*DAC_CNTL|0x2 turns off the extra brightness for gt*/
-    aty_st_8(DAC_CNTL, i, info2);
-    aty_st_8(DAC_REGS + DAC_MASK, 0xff, info2);
+    aty_st_8(DAC_CNTL, i, info);
+    aty_st_8(DAC_REGS + DAC_MASK, 0xff, info);
     eieio();
-    scale = ((info2->chip_class != CLASS_GX) &&
-	     (info2->current_par.hw.gx.cmode == CMODE_16)) ? 3 : 0;
-    info2->aty_cmap_regs->windex = regno << scale;
+    scale = ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID) &&
+	     (info->current_par.crtc.bpp == 16)) ? 3 : 0;
+    info->aty_cmap_regs->windex = regno << scale;
     eieio();
-    info2->aty_cmap_regs->lut = red << scale;
+    info->aty_cmap_regs->lut = red << scale;
     eieio();
-    info2->aty_cmap_regs->lut = green << scale;
+    info->aty_cmap_regs->lut = green << scale;
     eieio();
-    info2->aty_cmap_regs->lut = blue << scale;
+    info->aty_cmap_regs->lut = blue << scale;
     eieio();
     if (regno < 16) {
 #ifdef FBCON_HAS_CFB16
 	fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno;
 #endif
+#ifdef FBCON_HAS_CFB24
+	fbcon_cfb24_cmap[regno] = (regno << 16) | (regno << 8) | regno;
+#endif
 #ifdef FBCON_HAS_CFB32
 	fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) |
 				  (regno << 8) | regno;
@@ -2765,14 +3091,15 @@
     if (!width || !height)
 	return;
 
-    pitch_value = info->current_par.vxres;
-#if 0
-    if (par->hw.gx.cmode == CMODE_24) {
+    pitch_value = info->current_par.crtc.vxres;
+    if (info->current_par.crtc.bpp == 24) {
 	/* In 24 bpp, the engine is in 8 bpp - this requires that all */
 	/* horizontal coordinates and widths must be adjusted */
-	pitch_value = pitch_value * 3;
+	pitch_value *= 3;
+	srcx *= 3;
+	dstx *= 3;
+	width *= 3;
     }
-#endif
 
     if (srcy < dsty) {
 	dsty += height - 1;
@@ -2806,6 +3133,13 @@
     if (!width || !height)
 	return;
 
+    if (info->current_par.crtc.bpp == 24) {
+	/* In 24 bpp, the engine is in 8 bpp - this requires that all */
+	/* horizontal coordinates and widths must be adjusted */
+	dstx *= 3;
+	width *= 3;
+    }
+
     wait_for_fifo(3, info);
     aty_st_le32(DP_FRGD_CLR, color, info);
     aty_st_le32(DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE,
@@ -2823,6 +3157,13 @@
 static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx,
 			    int height, int width)
 {
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+	return;
+#endif
+
     sx *= p->fontwidth;
     sy *= p->fontheight;
     dx *= p->fontwidth;
@@ -2837,7 +3178,15 @@
 static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy,
 			    int sx, int height, int width)
 {
-    u32 bgx = attr_bgcol_ec(p, conp);
+    u32 bgx;
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+	return;
+#endif
+
+    bgx = attr_bgcol_ec(p, conp);
     bgx |= (bgx << 8);
     bgx |= (bgx << 16);
 
@@ -2854,13 +3203,28 @@
 static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c,
 			    int yy, int xx)
 {
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+	return;
+#endif
+
     wait_for_idle((struct fb_info_aty *)p->fb_info);
     fbcon_cfb8_putc(conp, p, c, yy, xx);
 }
 
 static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
-			     const unsigned short *s, int count, int yy, int xx)
+			     const unsigned short *s, int count, int yy,
+			     int xx)
 {
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+	return;
+#endif
+
     wait_for_idle((struct fb_info_aty *)p->fb_info);
     fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
 }
@@ -2868,7 +3232,7 @@
 static struct display_switch fbcon_aty8 = {
     fbcon_cfb8_setup, fbcon_aty_bmove, fbcon_aty_clear, fbcon_aty8_putc,
     fbcon_aty8_putcs, fbcon_cfb8_revc, NULL, NULL, fbcon_cfb8_clear_margins,
-    FONTWIDTH(8)
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 
@@ -2876,20 +3240,73 @@
 static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, int c,
 			     int yy, int xx)
 {
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+	return;
+#endif
+
     wait_for_idle((struct fb_info_aty *)p->fb_info);
     fbcon_cfb16_putc(conp, p, c, yy, xx);
 }
 
 static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p,
-			      const unsigned short *s, int count, int yy, int xx)
+			      const unsigned short *s, int count, int yy,
+			      int xx)
 {
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+	return;
+#endif
+
     wait_for_idle((struct fb_info_aty *)p->fb_info);
     fbcon_cfb16_putcs(conp, p, s, count, yy, xx);
 }
 
 static struct display_switch fbcon_aty16 = {
     fbcon_cfb16_setup, fbcon_aty_bmove, fbcon_aty_clear, fbcon_aty16_putc,
-    fbcon_aty16_putcs, fbcon_cfb16_revc, NULL, NULL, NULL, FONTWIDTH(8)
+    fbcon_aty16_putcs, fbcon_cfb16_revc, NULL, NULL, fbcon_cfb16_clear_margins,
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+#ifdef FBCON_HAS_CFB24
+static void fbcon_aty24_putc(struct vc_data *conp, struct display *p, int c,
+			     int yy, int xx)
+{
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+	return;
+#endif
+
+    wait_for_idle((struct fb_info_aty *)p->fb_info);
+    fbcon_cfb24_putc(conp, p, c, yy, xx);
+}
+
+static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p,
+			      const unsigned short *s, int count, int yy,
+			      int xx)
+{
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+	return;
+#endif
+
+    wait_for_idle((struct fb_info_aty *)p->fb_info);
+    fbcon_cfb24_putcs(conp, p, s, count, yy, xx);
+}
+
+static struct display_switch fbcon_aty24 = {
+    fbcon_cfb24_setup, fbcon_cfb24_bmove, fbcon_cfb24_clear, fbcon_aty24_putc,
+    fbcon_aty24_putcs, fbcon_cfb24_revc, NULL, NULL, fbcon_cfb24_clear_margins,
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 
@@ -2897,19 +3314,35 @@
 static void fbcon_aty32_putc(struct vc_data *conp, struct display *p, int c,
 			     int yy, int xx)
 {
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+	return;
+#endif
+
     wait_for_idle((struct fb_info_aty *)p->fb_info);
     fbcon_cfb32_putc(conp, p, c, yy, xx);
 }
 
 static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p,
-			      const unsigned short *s, int count, int yy, int xx)
+			      const unsigned short *s, int count, int yy,
+			      int xx)
 {
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && currcon == fb->vtconsole)
+	return;
+#endif
+
     wait_for_idle((struct fb_info_aty *)p->fb_info);
     fbcon_cfb32_putcs(conp, p, s, count, yy, xx);
 }
 
 static struct display_switch fbcon_aty32 = {
     fbcon_cfb32_setup, fbcon_aty_bmove, fbcon_aty_clear, fbcon_aty32_putc,
-    fbcon_aty32_putcs, fbcon_cfb32_revc, NULL, NULL, NULL, FONTWIDTH(8)
+    fbcon_aty32_putcs, fbcon_cfb32_revc, NULL, NULL, fbcon_cfb32_clear_margins,
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
diff -u --recursive --new-file v2.1.111/linux/drivers/video/bwtwofb.c linux/drivers/video/bwtwofb.c
--- v2.1.111/linux/drivers/video/bwtwofb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/bwtwofb.c	Sun Jul 26 14:40:19 1998
@@ -0,0 +1,222 @@
+/* $Id: bwtwofb.c,v 1.1 1998/07/21 14:50:48 jj Exp $
+ * bwtwofb.c: BWtwo frame buffer driver
+ *
+ * Copyright (C) 1998 Jakub Jelinek   (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Eddie C. Dost   (ecd@skynet.be)
+ * Copyright (C) 1998 Pavel Machek    (pavel@ucw.cz)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/sched.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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/selection.h>
+
+#include "sbusfb.h"
+#include <asm/io.h>
+#ifndef __sparc_v9__
+#include <asm/sun4paddr.h>
+#endif
+
+#include "fbcon-mfb.h"
+
+/* OBio addresses for the bwtwo registers */
+#define BWTWO_REGISTER_OFFSET 0x400000
+
+struct bw2_regs {
+	struct bt_regs		bt;
+	volatile u8		control;
+	volatile u8		status;
+	volatile u8		cursor_start;
+	volatile u8		cursor_end;
+	volatile u8		h_blank_start;
+	volatile u8		h_blank_end;
+	volatile u8		h_sync_start;
+	volatile u8		h_sync_end;
+	volatile u8		comp_sync_end;
+	volatile u8		v_blank_start_high;
+	volatile u8		v_blank_start_low;
+	volatile u8		v_blank_end;
+	volatile u8		v_sync_start;
+	volatile u8		v_sync_end;
+	volatile u8		xfer_holdoff_start;
+	volatile u8		xfer_holdoff_end;
+};
+
+/* Status Register Constants */
+#define BWTWO_SR_RES_MASK	0x70
+#define BWTWO_SR_1600_1280	0x50
+#define BWTWO_SR_1152_900_76_A	0x40
+#define BWTWO_SR_1152_900_76_B	0x60
+#define BWTWO_SR_ID_MASK	0x0f
+#define BWTWO_SR_ID_MONO	0x02
+#define BWTWO_SR_ID_MONO_ECL	0x03
+#define BWTWO_SR_ID_MSYNC	0x04
+
+/* Control Register Constants */
+#define BWTWO_CTL_ENABLE_INTS   0x80
+#define BWTWO_CTL_ENABLE_VIDEO  0x40
+#define BWTWO_CTL_ENABLE_TIMING 0x20
+#define BWTWO_CTL_ENABLE_CURCMP 0x10
+#define BWTWO_CTL_XTAL_MASK     0x0C
+#define BWTWO_CTL_DIVISOR_MASK  0x03
+
+/* Status Register Constants */
+#define BWTWO_STAT_PENDING_INT  0x80
+#define BWTWO_STAT_MSENSE_MASK  0x70
+#define BWTWO_STAT_ID_MASK      0x0f
+
+static struct sbus_mmap_map bw2_mmap_map[] = {
+	{ 0,			0,			SBUS_MMAP_FBSIZE(1) },
+	{ 0,			0,			0		    }
+};
+
+static void bw2_blank (struct fb_info_sbusfb *fb)
+{
+	fb->s.bw2.regs->control &= ~BWTWO_CTL_ENABLE_VIDEO;
+}
+
+static void bw2_unblank (struct fb_info_sbusfb *fb)
+{
+	fb->s.bw2.regs->control |= BWTWO_CTL_ENABLE_VIDEO;
+}
+
+static void bw2_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
+{
+	p->screen_base += ((y_margin - fb->y_margin) * p->line_length + (x_margin - fb->x_margin)) >> 3;
+}
+
+static u8 bw2regs_1600[] __initdata = {
+	0x14, 0x8b,	0x15, 0x28,	0x16, 0x03,	0x17, 0x13,
+	0x18, 0x7b,	0x19, 0x05,	0x1a, 0x34,	0x1b, 0x2e,
+	0x1c, 0x00,	0x1d, 0x0a,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x21,	0
+};
+
+static u8 bw2regs_ecl[] __initdata = {
+	0x14, 0x65,	0x15, 0x1e,	0x16, 0x04,	0x17, 0x0c,
+	0x18, 0x5e,	0x19, 0x03,	0x1a, 0xa7,	0x1b, 0x23,
+	0x1c, 0x00,	0x1d, 0x08,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x20,	0
+};
+
+static u8 bw2regs_analog[] __initdata = {
+	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x03,	0x17, 0x13,
+	0x18, 0xb0,	0x19, 0x03,	0x1a, 0xa6,	0x1b, 0x22,
+	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x20,	0
+};
+
+static u8 bw2regs_76hz[] __initdata = {
+	0x14, 0xb7,	0x15, 0x27,	0x16, 0x03,	0x17, 0x0f,
+	0x18, 0xae,	0x19, 0x03,	0x1a, 0xae,	0x1b, 0x2a,
+	0x1c, 0x01,	0x1d, 0x09,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x24,	0
+};
+
+static u8 bw2regs_66hz[] __initdata = {
+	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x04,	0x17, 0x14,
+	0x18, 0xae,	0x19, 0x03,	0x1a, 0xa8,	0x1b, 0x24,
+	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x20,	0
+};
+
+static char idstring[60] __initdata = { 0 };
+
+__initfunc(char *bwtwofb_init(struct fb_info_sbusfb *fb))
+{
+	struct fb_fix_screeninfo *fix = &fb->fix;
+	struct display *disp = &fb->disp;
+	struct fbtype *type = &fb->type;
+#ifdef CONFIG_SUN4
+	unsigned long phys = SUN4_300_BWTWO_PHYSADDR;
+#else
+	unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr;
+#endif
+
+#ifndef FBCON_HAS_MFB
+	return NULL;
+#endif
+
+	if (!fb->s.bw2.regs) {
+		fb->s.bw2.regs = (struct bw2_regs *)sparc_alloc_io(phys+BWTWO_REGISTER_OFFSET, 0, 
+				sizeof(struct bw2_regs), "bw2_regs", fb->iospace, 0);
+		if (!prom_getbool(fb->prom_node, "width")) {
+			/* Ugh, broken PROM didn't initialize us.
+			 * Let's deal with this ourselves.
+			 */
+			u8 status, mon;
+			u8 *p;
+			int sizechange = 0;
+
+			status = fb->s.bw2.regs->status;
+			mon = status & BWTWO_SR_RES_MASK;
+			switch (status & BWTWO_SR_ID_MASK) {
+				case BWTWO_SR_ID_MONO_ECL:
+					if (mon == BWTWO_SR_1600_1280) {
+						p = bw2regs_1600;
+						fb->type.fb_width = 1600;
+						fb->type.fb_height = 1280;
+						sizechange = 1;
+					} else
+						p = bw2regs_ecl;
+					break;
+				case BWTWO_SR_ID_MONO:
+					p = bw2regs_analog;
+					break;
+				case BWTWO_SR_ID_MSYNC:
+					if (mon == BWTWO_SR_1152_900_76_A ||
+					    mon == BWTWO_SR_1152_900_76_B)
+						p = bw2regs_76hz;
+					else
+						p = bw2regs_66hz;
+					break;
+				default:
+					prom_printf("bw2: can't handle SR %02x\n",
+						    status);
+					prom_halt();
+					return NULL; /* fool gcc. */
+			}
+			for ( ; *p; p += 2)
+				((u8 *)fb->s.bw2.regs)[p[0]] = p[1];
+		}
+	}
+
+	strcpy(fb->info.modename, "BWtwo");
+	strcpy(fix->id, "BWtwo");
+	fix->line_length = fb->var.xres_virtual>>3;
+	
+	disp->scrollmode = SCROLL_YREDRAW;
+	if (!disp->screen_base)
+		disp->screen_base = (char *)sparc_alloc_io(phys, 0, 
+			type->fb_size, "bw2_ram", fb->iospace, 0);
+	disp->screen_base += (fix->line_length * fb->y_margin + fb->x_margin) >> 3;
+	fb->dispsw = fbcon_mfb;
+	fix->visual = FB_VISUAL_MONO01;
+
+	fb->blank = bw2_blank;
+	fb->unblank = bw2_unblank;
+	fb->margins = bw2_margins;
+	
+	fb->physbase = phys;
+	fb->mmap_map = bw2_mmap_map;
+
+#ifdef __sparc_v9__
+	sprintf(idstring, "bwtwo at %016lx", phys);
+#else	
+	sprintf(idstring, "bwtwo at %x.%08lx", fb->iospace, phys);
+#endif
+	
+	return idstring;
+}
diff -u --recursive --new-file v2.1.111/linux/drivers/video/cgsixfb.c linux/drivers/video/cgsixfb.c
--- v2.1.111/linux/drivers/video/cgsixfb.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/cgsixfb.c	Sun Jul 26 14:40:19 1998
@@ -1,4 +1,4 @@
-/* $Id: cgsixfb.c,v 1.4 1998/07/21 10:36:53 jj Exp $
+/* $Id: cgsixfb.c,v 1.7 1998/07/22 12:44:59 jj Exp $
  * cgsixfb.c: CGsix (GX,GXplus) frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
@@ -237,8 +237,8 @@
 	do {
 		i = fbc->s;
 	} while (i & 0x10000000);
-	fbc->fg = attr_bg_col_ec(conp);
-	fbc->bg = attr_bg_col_ec(conp);
+	fbc->fg = attr_bgcol_ec(p,conp);
+	fbc->bg = attr_bgcol_ec(p,conp);
 	fbc->pixelm = ~(0);
 	fbc->alu = 0xea80ff00;
 	fbc->s = 0;
@@ -264,7 +264,7 @@
 	} while (i < 0 && (i & 0x20000000));
 }
 
-static void cg6_fill(struct fb_info_sbusfb *fb, int s,
+static void cg6_fill(struct fb_info_sbusfb *fb, struct display *p, int s,
 		     int count, unsigned short *boxes)
 {
 	int i;
@@ -273,8 +273,8 @@
 	do {
 		i = fbc->s;
 	} while (i & 0x10000000);
-	fbc->fg = attr_bg_col(s);
-	fbc->bg = attr_bg_col(s);
+	fbc->fg = attr_bgcol(p,s);
+	fbc->bg = attr_bgcol(p,s);
 	fbc->pixelm = ~(0);
 	fbc->alu = 0xea80ff00;
 	fbc->s = 0;
@@ -301,11 +301,15 @@
 
 	if (p->fontheightlog) {
 		y = fb->y_margin + (yy << p->fontheightlog);
-		i = ((c & 0xff) << p->fontheightlog);
+		i = ((c & p->charmask) << p->fontheightlog);
 	} else {
 		y = fb->y_margin + (yy * p->fontheight);
-		i = (c & 0xff) * p->fontheight;
+		i = (c & p->charmask) * p->fontheight;
 	}
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+	fd = p->fontdata + i;
+	x = fb->x_margin + xx * 8;
+#else
 	if (p->fontwidth <= 8)
 		fd = p->fontdata + i;
 	else
@@ -314,11 +318,12 @@
 		x = fb->x_margin + (xx << p->fontwidthlog);
 	else
 		x = fb->x_margin + (xx * p->fontwidth);
+#endif
 	do {
 		i = fbc->s;
 	} while (i & 0x10000000);
-	fbc->fg = attr_fg_col(c);
-	fbc->bg = attr_bg_col(c);
+	fbc->fg = attr_fgcol(p,c);
+	fbc->bg = attr_bgcol(p,c);
 	fbc->mode = 0x140000;
 	fbc->alu = 0xe880fc30;
 	fbc->pixelm = ~(0);
@@ -330,15 +335,19 @@
 	fbc->x0 = x;
 	fbc->x1 = x + p->fontwidth - 1;
 	fbc->y0 = y;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
 	if (p->fontwidth <= 8) {
+#endif
 		for (i = 0; i < p->fontheight; i++)
 			fbc->font = *fd++ << 24;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
 	} else {
 		for (i = 0; i < p->fontheight; i++) {
 			fbc->font = *(u16 *)fd << 16;
 			fd += 2;
 		}
 	}
+#endif
 }
 
 static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
@@ -352,8 +361,8 @@
 	do {
 		i = fbc->s;
 	} while (i & 0x10000000);
-	fbc->fg = attr_fg_col(*s);
-	fbc->bg = attr_bg_col(*s);
+	fbc->fg = attr_fgcol(p,*s);
+	fbc->bg = attr_bgcol(p,*s);
 	fbc->mode = 0x140000;
 	fbc->alu = 0xe880fc30;
 	fbc->pixelm = ~(0);
@@ -362,15 +371,21 @@
 	fbc->pm = 0xff;
 	x = fb->x_margin;
 	y = fb->y_margin;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+	x += xx * 8;
+#else
 	if (p->fontwidthlog)
 		x += (xx << p->fontwidthlog);
 	else
 		x += xx * p->fontwidth;
+#endif
 	if (p->fontheightlog)
 		y += (yy << p->fontheightlog);
 	else
 		y += (yy * p->fontheight);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
 	if (p->fontwidth <= 8) {
+#endif
 		while (count >= 4) {
 			count -= 4;
 			fbc->incx = 0;
@@ -379,20 +394,23 @@
 			fbc->x1 = (x += 4 * p->fontwidth) - 1;
 			fbc->y0 = y;
 			if (p->fontheightlog) {
-				fd1 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
-				fd2 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
-				fd3 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
-				fd4 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
+				fd1 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+				fd2 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+				fd3 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+				fd4 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
 			} else {
-				fd1 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
-				fd2 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
-				fd3 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
-				fd4 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
+				fd1 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+				fd2 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+				fd3 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+				fd4 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
 			}
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
 			if (p->fontwidth == 8) {
+#endif
 				for (i = 0; i < p->fontheight; i++)
 					fbc->font = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) 
 						<< 8)) << 8)) << 8);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
 			} else {
 				for (i = 0; i < p->fontheight; i++)
 					fbc->font = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) 
@@ -408,17 +426,18 @@
 			fbc->x1 = (x += 2 * p->fontwidth) - 1;
 			fbc->y0 = y;
 			if (p->fontheightlog) {
-				fd1 = p->fontdata + ((*s++ & 0xff) << (p->fontheightlog + 1));
-				fd2 = p->fontdata + ((*s++ & 0xff) << (p->fontheightlog + 1));
+				fd1 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1));
+				fd2 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1));
 			} else {
-				fd1 = p->fontdata + (((*s++ & 0xff) * p->fontheight) << 1);
-				fd2 = p->fontdata + (((*s++ & 0xff) * p->fontheight) << 1);
+				fd1 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1);
+				fd2 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1);
 			}
 			for (i = 0; i < p->fontheight; i++) {
 				fbc->font = ((((u32)*(u16 *)fd1) << p->fontwidth) | ((u32)*(u16 *)fd2)) << (16 - p->fontwidth);
 				fd1 += 2; fd2 += 2;
 			}
 		}
+#endif
 	}
 	while (count) {
 		count--;
@@ -428,13 +447,16 @@
 		fbc->x1 = (x += p->fontwidth) - 1;
 		fbc->y0 = y;
 		if (p->fontheightlog)
-			i = ((*s++ & 0xff) << p->fontheightlog);
+			i = ((*s++ & p->charmask) << p->fontheightlog);
 		else
-			i = ((*s++ & 0xff) * p->fontheight);
+			i = ((*s++ & p->charmask) * p->fontheight);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
 		if (p->fontwidth <= 8) {
+#endif
 			fd1 = p->fontdata + i;
 			for (i = 0; i < p->fontheight; i++)
 				fbc->font = *fd1++ << 24;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
 		} else {
 			fd1 = p->fontdata + (i << 1);
 			for (i = 0; i < p->fontheight; i++) {
@@ -442,6 +464,7 @@
 				fd1 += 2;
 			}
 		}
+#endif
 	}
 }
 
@@ -466,7 +489,6 @@
 static void cg6_restore_palette (struct fb_info_sbusfb *fb)
 {
 	struct bt_regs *bt = fb->s.cg6.bt;
-	int i;
                 
 	bt->addr = 0;
 	bt->color_map = 0xffffffff;
@@ -592,10 +614,7 @@
 	strcpy(fb->info.modename, "CGsix");
 		
 	strcpy(fix->id, "CGsix");
-	fix->smem_start = (char *)phys + CG6_RAM_OFFSET;
 	fix->line_length = fb->var.xres_virtual;
-	fix->mmio_start = (char *)phys + CG6_FBC_OFFSET;
-	fix->mmio_len = PAGE_SIZE;
 	fix->accel = FB_ACCEL_SUN_CGSIX;
 	
 	var->accel_flags = FB_ACCELF_TEXT;
@@ -648,7 +667,12 @@
 	default: p = "i386"; break;
 	}
 	                                                                        
-	sprintf(idstring, "cgsix at %02x.%08lx TEC Rev %x CPU %s Rev %x", fb->iospace, phys, 
+	sprintf(idstring, 
+#ifdef __sparc_v9__
+		    "cgsix at %016lx TEC Rev %x CPU %s Rev %x", phys, 
+#else	
+		    "cgsix at %x.%08lx TEC Rev %x CPU %s Rev %x", fb->iospace, phys, 
+#endif
 		    (fb->s.cg6.thc->thc_misc >> CG6_THC_MISC_REV_SHIFT) & CG6_THC_MISC_REV_MASK,
 		    p, conf >> CG6_FHC_REV_SHIFT & CG6_FHC_REV_MASK);
 		    
diff -u --recursive --new-file v2.1.111/linux/drivers/video/cgthreefb.c linux/drivers/video/cgthreefb.c
--- v2.1.111/linux/drivers/video/cgthreefb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/cgthreefb.c	Sun Jul 26 14:40:19 1998
@@ -0,0 +1,247 @@
+/* $Id: cgthreefb.c,v 1.1 1998/07/21 14:50:47 jj Exp $
+ * cgthreefb.c: CGthree frame buffer driver
+ *
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#include <linux/module.h>
+#include <linux/sched.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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/selection.h>
+
+#include "sbusfb.h"
+#include <asm/io.h>
+
+#include "fbcon-cfb8.h"
+
+/* Control Register Constants */
+#define CG3_CR_ENABLE_INTS      0x80
+#define CG3_CR_ENABLE_VIDEO     0x40
+#define CG3_CR_ENABLE_TIMING    0x20
+#define CG3_CR_ENABLE_CURCMP    0x10
+#define CG3_CR_XTAL_MASK        0x0c
+#define CG3_CR_DIVISOR_MASK     0x03
+
+/* Status Register Constants */
+#define CG3_SR_PENDING_INT      0x80
+#define CG3_SR_RES_MASK         0x70
+#define CG3_SR_1152_900_76_A    0x40
+#define CG3_SR_1152_900_76_B    0x60
+#define CG3_SR_ID_MASK          0x0f
+#define CG3_SR_ID_COLOR         0x01
+#define CG3_SR_ID_MONO          0x02
+#define CG3_SR_ID_MONO_ECL      0x03
+
+enum cg3_type {
+	CG3_AT_66HZ = 0,
+	CG3_AT_76HZ,
+	CG3_RDI
+};
+
+struct cg3_regs {
+	struct bt_regs	cmap;
+	volatile u8	control;
+	volatile u8	status;
+	volatile u8	cursor_start;
+	volatile u8	cursor_end;
+	volatile u8	h_blank_start;
+	volatile u8	h_blank_end;
+	volatile u8	h_sync_start;
+	volatile u8	h_sync_end;
+	volatile u8	comp_sync_end;
+	volatile u8	v_blank_start_high;
+	volatile u8	v_blank_start_low;
+	volatile u8	v_blank_end;
+	volatile u8	v_sync_start;
+	volatile u8	v_sync_end;
+	volatile u8	xfer_holdoff_start;
+	volatile u8	xfer_holdoff_end;
+};
+
+/* Offset of interesting structures in the OBIO space */
+#define CG3_REGS_OFFSET	     0x400000
+#define CG3_RAM_OFFSET	     0x800000
+
+static struct sbus_mmap_map cg3_mmap_map[] = {
+	{ CG3_MMAP_OFFSET,	CG3_RAM_OFFSET,		SBUS_MMAP_FBSIZE(1) },
+	{ 0,			0,			0		    }
+};
+
+/* The cg3 palette is loaded with 4 color values at each time  */
+/* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on */
+
+#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2))      /* (x/4)*3 */
+#define D4M4(x) ((x)&~0x3)                      /* (x/4)*4 */
+
+static void cg3_loadcmap (struct fb_info_sbusfb *fb, int index, int count)
+{
+	struct bt_regs *bt = &fb->s.cg3.regs->cmap;
+	u32 *i;
+	int steps;
+	        
+	i = (((u32 *)fb->color_map) + D4M3(index));
+	steps = D4M3(index+count-1) - D4M3(index)+3;
+	                        
+	*(volatile u8 *)&bt->addr = (u8)D4M4(index);
+	while (steps--)
+		bt->color_map = *i++;
+}
+
+static void cg3_blank (struct fb_info_sbusfb *fb)
+{
+	fb->s.cg3.regs->control &= ~CG3_CR_ENABLE_VIDEO;
+}
+
+static void cg3_unblank (struct fb_info_sbusfb *fb)
+{
+	fb->s.cg3.regs->control |= CG3_CR_ENABLE_VIDEO;
+}
+
+static void cg3_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
+{
+	p->screen_base += (y_margin - fb->y_margin) * p->line_length + (x_margin - fb->x_margin);
+}
+
+static u8 cg3regvals_66hz[] __initdata = {	/* 1152 x 900, 66 Hz */
+	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x04,	0x17, 0x14,
+	0x18, 0xae,	0x19, 0x03,	0x1a, 0xa8,	0x1b, 0x24,
+	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x20,	0
+};
+
+static u8 cg3regvals_76hz[] __initdata = {	/* 1152 x 900, 76 Hz */
+	0x14, 0xb7,	0x15, 0x27,	0x16, 0x03,	0x17, 0x0f,
+	0x18, 0xae,	0x19, 0x03,	0x1a, 0xae,	0x1b, 0x2a,
+	0x1c, 0x01,	0x1d, 0x09,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x24,	0
+};
+
+static u8 cg3regvals_rdi[] __initdata = {	/* 640 x 480, cgRDI */
+	0x14, 0x70,	0x15, 0x20,	0x16, 0x08,	0x17, 0x10,
+	0x18, 0x06,	0x19, 0x02,	0x1a, 0x31,	0x1b, 0x51,
+	0x1c, 0x06,	0x1d, 0x0c,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x22,	0
+};
+
+static u8 *cg3_regvals[] __initdata = {
+	cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi
+};
+
+static u_char cg3_dacvals[] __initdata = {
+	4, 0xff,	5, 0x00,	6, 0x70,	7, 0x00,	0
+};
+
+static char idstring[60] __initdata = { 0 };
+
+__initfunc(char *cgthreefb_init(struct fb_info_sbusfb *fb))
+{
+	struct fb_fix_screeninfo *fix = &fb->fix;
+	struct display *disp = &fb->disp;
+	struct fbtype *type = &fb->type;
+	unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr;
+	int cgRDI = strstr(fb->sbdp->prom_name, "cgRDI") != NULL;
+
+#ifndef FBCON_HAS_CFB8
+	return NULL;
+#endif
+
+	if (!fb->s.cg3.regs) {
+		fb->s.cg3.regs = (struct cg3_regs *)sparc_alloc_io(phys+CG3_REGS_OFFSET, 0, 
+				sizeof(struct cg3_regs), "cg3_regs", fb->iospace, 0);
+		if (cgRDI) {
+			char buffer[40];
+			char *p;
+			int ww, hh;
+		
+			*buffer = 0;
+			prom_getstring (fb->prom_node, "params", buffer, sizeof(buffer));
+			if (*buffer) {
+				ww = simple_strtoul (buffer, &p, 10);
+				if (ww && *p == 'x') {
+					hh = simple_strtoul (p + 1, &p, 10);
+					if (hh && *p == '-') {
+						if (type->fb_width != ww || type->fb_height != hh) {
+							type->fb_width = ww;
+							type->fb_height = hh;
+							return SBUSFBINIT_SIZECHANGE;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	strcpy(fb->info.modename, "CGthree");
+	strcpy(fix->id, "CGthree");
+	fix->line_length = fb->var.xres_virtual;
+	
+	disp->scrollmode = SCROLL_YREDRAW;
+	if (!disp->screen_base)
+		disp->screen_base = (char *)sparc_alloc_io(phys+CG3_RAM_OFFSET, 0, 
+			type->fb_size, "cg3_ram", fb->iospace, 0);
+	disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin;
+	fb->dispsw = fbcon_cfb8;
+
+	fb->margins = cg3_margins;
+	fb->loadcmap = cg3_loadcmap;
+	fb->blank = cg3_blank;
+	fb->unblank = cg3_unblank;
+	
+	fb->physbase = phys;
+	fb->mmap_map = cg3_mmap_map;
+	
+#ifdef __sparc_v9__	
+	sprintf(idstring, "%s at %016lx", cgRDI ? "cgRDI" : "cgthree", phys);
+#else
+	sprintf(idstring, "%s at %x.%08lx", cgRDI ? "cgRDI" : "cgthree", fb->iospace, phys);
+#endif
+	
+	if (!prom_getbool(fb->prom_node, "width")) {
+		/* Ugh, broken PROM didn't initialize us.
+		 * Let's deal with this ourselves.
+		 */
+		enum cg3_type type;
+		u8 *p;
+
+		if (cgRDI)
+			type = CG3_RDI;
+		else {
+			u8 status = fb->s.cg3.regs->status, mon;
+			if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) {
+				mon = status & CG3_SR_RES_MASK;
+				if (mon == CG3_SR_1152_900_76_A ||
+				    mon == CG3_SR_1152_900_76_B)
+					type = CG3_AT_76HZ;
+				else
+					type = CG3_AT_66HZ;
+			} else {
+				prom_printf("cgthree: can't handle SR %02x\n",
+					    status);
+				prom_halt();
+				return NULL; /* fool gcc. */
+			}
+		}
+
+		for (p = cg3_regvals[type]; *p; p += 2)
+			((u8 *)fb->s.cg3.regs)[p[0]] = p[1];
+
+		for (p = cg3_dacvals; *p; p += 2) {
+			*(volatile u8 *)&fb->s.cg3.regs->cmap.addr = p[0];
+			*(volatile u8 *)&fb->s.cg3.regs->cmap.control = p[1];
+		}
+	}
+
+	return idstring;
+}
diff -u --recursive --new-file v2.1.111/linux/drivers/video/clgenfb.c linux/drivers/video/clgenfb.c
--- v2.1.111/linux/drivers/video/clgenfb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/clgenfb.c	Sun Jul 26 14:40:19 1998
@@ -0,0 +1,2122 @@
+/*
+ * Based on retz3fb.c and clgen.c
+ */
+ 
+#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/zorro.h>
+#include <linux/init.h>
+#include <asm/amigahw.h>
+#include <asm/pgtable.h>
+#include <asm/delay.h>
+#include "fbcon.h"
+
+#include "fbcon.h"
+#include "fbcon-mfb.h"
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb16.h"
+#include "fbcon-cfb24.h"
+#include "fbcon-cfb32.h"
+
+#include "clgenfb.h"
+
+#define CLGEN_VERSION "1.4 ?"
+/* #define DEBUG if(1) */
+#define DEBUG if(0)
+
+#define arraysize(x)    (sizeof(x)/sizeof(*(x)))
+
+/* zorro IDs */
+#define ZORRO_PROD_HELFRICH_SD64_RAM				0x08930A00
+#define ZORRO_PROD_HELFRICH_SD64_REG				0x08930B00
+#define ZORRO_PROD_HELFRICH_PICCOLO_RAM				0x08930500
+#define ZORRO_PROD_HELFRICH_PICCOLO_REG				0x08930600
+#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM	0x08770B00
+#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG	0x08770C00
+#define ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM			0x08910200
+#define ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG			0x08910100
+#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3			0x08771800
+
+/* board types */
+#define BT_NONE     0
+#define BT_SD64     1
+#define BT_PICCOLO  2
+#define BT_PICASSO  3
+#define BT_SPECTRUM 4
+#define BT_PICASSO4 5
+
+#define MAX_NUM_BOARDS 7
+
+#define TRUE  1
+#define FALSE 0 
+
+struct clgenfb_par
+{
+    struct fb_var_screeninfo var;
+
+    __u32 line_length;  /* in BYTES! */
+    __u32 visual;
+    __u32 type;
+
+    long freq;
+    long nom;
+    long den;
+    long div;
+
+    long HorizRes;   /* The x resolution in pixel */
+    long HorizTotal;
+    long HorizDispEnd;
+    long HorizBlankStart;
+    long HorizBlankEnd;
+    long HorizSyncStart;
+    long HorizSyncEnd;
+
+    long VertRes;   /* the physical y resolution in scanlines */
+    long VertTotal;
+    long VertDispEnd;
+    long VertSyncStart;
+    long VertSyncEnd;
+    long VertBlankStart;
+    long VertBlankEnd;
+};
+
+/* info about board */
+struct clgenfb_info
+{
+    struct fb_info_gen gen;
+
+    int keyRAM;  /* RAM, REG zorro board keys */
+    int keyREG;
+    unsigned long fbmem;
+    volatile unsigned char *regs;
+    unsigned long mem;
+    unsigned long size;
+    int btype;
+    int smallboard;
+    unsigned char SFR; /* Shadow of special function register */
+    
+    struct clgenfb_par currentmode;
+};
+
+static struct display disp;
+
+static struct clgenfb_info boards[MAX_NUM_BOARDS];  /* the boards */
+static struct clgenfb_info *fb_info=NULL;  /* pointer to current board */
+
+/*
+ *    Predefined Video Modes
+ */
+
+static struct fb_videomode clgenfb_predefined[] __initdata =
+{
+	{   "Autodetect", /* autodetect mode */
+	    { 0 }
+	},
+
+	{   "640x480", /* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */
+	    { 
+		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_ACCEL_NONE, 40000, 32, 32, 33, 10, 96, 2,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	    }
+	},
+
+	/* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */
+	/* 
+	    Modeline from XF86Config:
+	    Mode "1024x768" 80  1024 1136 1340 1432  768 770 774 805
+	*/
+	{
+	    "1024x768",
+	    { 
+		1024, 768, 1024, 768, 0, 0, 8, 0, 
+		{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 
+		0, 0, -1, -1, FB_ACCEL_NONE, 12500, 92, 112, 31, 2, 204, 4,
+		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+	    }
+	}
+};
+
+#define NUM_TOTAL_MODES    arraysize(clgenfb_predefined)
+static struct fb_var_screeninfo clgenfb_default;
+
+/*
+ *    Frame Buffer Name
+ */
+
+static char clgenfb_name[16] = "CLgen";
+
+/****************************************************************************/
+/**** BEGIN PROTOTYPES ******************************************************/
+
+/*--- Interface used by the world ------------------------------------------*/
+void clgenfb_init(void);
+void clgenfb_setup(char *options, int *ints);
+int clgenfb_open(struct fb_info *info, int user);
+int clgenfb_release(struct fb_info *info, int user);
+int clgenfb_ioctl(struct inode *inode, struct file *file, 
+		  unsigned int cmd, unsigned long arg, int con, 
+		  struct fb_info *info);
+
+/* function table of the above functions */
+static struct fb_ops clgenfb_ops =
+{
+    clgenfb_open,
+    clgenfb_release,
+    fbgen_get_fix,   /* using the generic functions */
+    fbgen_get_var,   /* makes things much easier... */
+    fbgen_set_var,
+    fbgen_get_cmap,
+    fbgen_set_cmap,
+    fbgen_pan_display,
+    clgenfb_ioctl,
+    NULL
+};
+
+/*--- Hardware Specific Routines -------------------------------------------*/
+static void clgen_detect(void);
+static int  clgen_encode_fix(struct fb_fix_screeninfo *fix, const void *par,
+			     struct fb_info_gen *info);
+static int  clgen_decode_var(const struct fb_var_screeninfo *var, void *par,
+			     struct fb_info_gen *info);
+static int  clgen_encode_var(struct fb_var_screeninfo *var, const void *par,
+			     struct fb_info_gen *info);
+static void clgen_get_par(void *par, struct fb_info_gen *info);
+static void clgen_set_par(const void *par, struct fb_info_gen *info);
+static int  clgen_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			   unsigned *blue, unsigned *transp,
+			   struct fb_info *info);
+static int  clgen_setcolreg(unsigned regno, unsigned red, unsigned green,
+			    unsigned blue, unsigned transp,
+			    struct fb_info *info);
+static int  clgen_pan_display(const struct fb_var_screeninfo *var,
+			      struct fb_info_gen *info);
+static int  clgen_blank(int blank_mode, struct fb_info_gen *info);
+
+static struct display_switch *clgen_get_dispsw(const void *par,
+					       struct fb_info_gen *info);
+
+/* function table of the above functions */
+static struct fbgen_hwswitch clgen_hwswitch = 
+{
+    clgen_detect,
+    clgen_encode_fix,
+    clgen_decode_var,
+    clgen_encode_var,
+    clgen_get_par,
+    clgen_set_par,
+    clgen_getcolreg, 
+    clgen_setcolreg,
+    clgen_pan_display,
+    clgen_blank,
+    clgen_get_dispsw
+};
+
+/* Text console acceleration */
+
+#ifdef FBCON_HAS_CFB8
+static void fbcon_clgen8_bmove(struct display *p, int sy, int sx, 
+				int dy, int dx, int height, int width);
+static void fbcon_clgen8_clear(struct vc_data *conp, struct display *p, 
+				int sy, int sx, int height, int width);
+
+static struct display_switch fbcon_clgen_8 = {
+    fbcon_cfb8_setup,
+    fbcon_clgen8_bmove,
+    fbcon_clgen8_clear,
+    fbcon_cfb8_putc,
+    fbcon_cfb8_putcs,
+    fbcon_cfb8_revc,
+    NULL,
+    NULL,
+    fbcon_cfb8_clear_margins,
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+
+
+/*--- Internal routines ----------------------------------------------------*/
+static void init_vgachip(void);
+static void switch_monitor(int on);
+
+static void		WGen( int regnum, unsigned char val );
+static unsigned char	RGen( int regnum );
+static void		WSeq( unsigned char regnum, unsigned char val );
+static unsigned char	RSeq( unsigned char regnum );
+static void		WCrt( unsigned char regnum, unsigned char val );
+static unsigned char	RCrt( unsigned char regnum );
+static void		WGfx( unsigned char regnum, unsigned char val );
+static unsigned char	RGfx( unsigned char regnum );
+static void		WAttr( unsigned char regnum, unsigned char val );
+static void		AttrOn( void );
+static unsigned char	RAttr( unsigned char regnum );
+static void		WHDR( unsigned char val );
+static unsigned char	RHDR( void );
+static void		WSFR( unsigned char val );
+static void		WSFR2( unsigned char val );
+static void		WClut( unsigned char regnum, unsigned char red, 
+						     unsigned char green, 
+						     unsigned char blue );
+static void		RClut( unsigned char regnum, unsigned char *red, 
+						     unsigned char *green, 
+						     unsigned char *blue );
+static void		clgen_WaitBLT( void );
+static void		clgen_BitBLT (u_short curx, u_short cury,
+				      u_short destx, u_short desty,
+				      u_short width, u_short height, 
+				      u_short line_length);
+static void		clgen_RectFill (u_short x, u_short y,
+					u_short width, u_short height,
+					u_char color, u_short line_length);
+
+static void		bestclock(long freq, long *best, 
+				  long *nom, long *den, 
+				  long *div, long maxfreq);
+
+/*** END   PROTOTYPES ********************************************************/
+/*****************************************************************************/
+/*** BEGIN Interface Used by the World ***************************************/
+
+static int opencount = 0;
+
+/*--- Open /dev/fbx ---------------------------------------------------------*/
+int clgenfb_open(struct fb_info *info, int user)
+{
+    MOD_INC_USE_COUNT;
+    if (opencount++ == 0) switch_monitor(1);
+    return 0;
+}
+
+/*--- Close /dev/fbx --------------------------------------------------------*/
+int clgenfb_release(struct fb_info *info, int user)
+{
+    if (--opencount == 0) switch_monitor(0);
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+/*--- handle /dev/fbx ioctl calls ------------------------------------------*/
+int clgenfb_ioctl(struct inode *inode, struct file *file,
+                  unsigned int cmd, unsigned long arg, int con,
+                  struct fb_info *info)
+{
+    printk(">clgenfb_ioctl()\n");
+    /* Nothing exciting here... */
+    printk("<clgenfb_ioctl()\n");
+    return -EINVAL;
+}
+
+/**** END   Interface used by the World *************************************/
+/****************************************************************************/
+/**** BEGIN Hardware specific Routines **************************************/
+
+static void clgen_detect(void)
+{
+    printk(">clgen_detect()\n");
+    printk("<clgen_detect()\n");
+}
+
+static int clgen_encode_fix(struct fb_fix_screeninfo *fix, const void *par,
+			    struct fb_info_gen *info)
+{
+    struct clgenfb_par  *_par  = (struct clgenfb_par*) par;
+    struct clgenfb_info *_info = (struct clgenfb_info*)info;
+    
+    memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+    strcpy(fix->id, clgenfb_name);
+	
+    fix->smem_start	= (char*)_info->fbmem;
+    
+    /* monochrome: only 1 memory plane */
+    /* 8 bit and above: Use whole memory area */
+    fix->smem_len       = _par->var.bits_per_pixel == 1 ? _info->size / 4 
+							: _info->size;
+    fix->type		= _par->type;
+    fix->type_aux	= 0;
+    fix->visual		= _par->visual;
+    fix->xpanstep	= 1;
+    fix->ypanstep	= 1;
+    fix->ywrapstep	= 0;
+    fix->line_length	= _par->line_length;
+    fix->mmio_start	= (char *)_info->regs;
+    fix->mmio_len	= 0x10000;
+    fix->accel		= FB_ACCEL_NONE;
+
+    return 0;
+}
+
+static int clgen_decode_var(const struct fb_var_screeninfo *var, void *par,
+			    struct fb_info_gen *info)
+{
+    long freq;
+    int  xres, hfront, hsync, hback;
+    int  yres, vfront, vsync, vback;
+    int  nom,den; /* translyting from pixels->bytes */
+    int  i;
+    static struct
+    {
+	int xres,yres;
+    }
+    modes[] = { {1600,1280}, {1280,1024}, {1024,768}, 
+		{800,600}, {640,480}, {-1,-1} };
+
+    struct clgenfb_par *_par = (struct clgenfb_par *)par;
+
+    fb_info = (struct clgenfb_info*)info;
+    printk("clgen_decode_var()\n");
+
+    printk("Requested: %dx%dx%d\n", var->xres,var->yres,var->bits_per_pixel);
+    printk("  virtual: %dx%d\n", var->xres_virtual,var->yres_virtual);
+    printk("   offset: (%d,%d)\n", var->xoffset, var->yoffset);
+    printk("grayscale: %d\n", var->grayscale);
+#if 0
+    printk(" activate: 0x%x\n", var->activate);
+    printk(" pixclock: %d\n", var->pixclock);
+    printk("  htiming: %d;%d  %d\n", var->left_margin,var->right_margin,var->hsync_len);
+    printk("  vtiming: %d;%d  %d\n", var->upper_margin,var->lower_margin,var->vsync_len);
+    printk("     sync: 0x%x\n", var->sync);
+    printk("    vmode: 0x%x\n", var->vmode);
+#endif
+
+    _par->var = *var;
+
+    switch (var->bits_per_pixel)
+    {
+    case 1:  nom = 4; den = 8; break;   /* 8 pixel per byte, only 1/4th of mem usable */
+    case 8:  nom = 1; den = 1; break;   /* 1 pixel == 1 byte */
+    case 16: nom = 2; den = 1; break;   /* 2 bytes per pixel */
+    case 24: nom = 3; den = 1; break;   /* 3 bytes per pixel */
+    case 32: nom = 4; den = 1; break;	/* 4 bytes per pixel */
+    default:
+	printk("clgen: mode %dx%dx%d rejected...color depth not supported.\n",
+		var->xres, var->yres, var->bits_per_pixel);
+	return -EINVAL;
+    }
+
+    if (_par->var.xres*nom/den * _par->var.yres > fb_info->size)
+    {
+	printk("clgen: mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
+		var->xres, var->yres, var->bits_per_pixel);
+	return -EINVAL;
+    }
+    
+    /* use highest possible virtual resolution */
+    if (_par->var.xres_virtual == -1 &&
+	_par->var.xres_virtual == -1)
+    {
+	printk("clgen: using maximum available virtual resolution\n");
+	for (i=0; modes[i].xres != -1; i++)
+	{
+	    if (modes[i].xres*nom/den * modes[i].yres < fb_info->size/2)
+		break;
+	}
+	if (modes[i].xres == -1)
+	{
+	    printk("clgen: could not find a virtual resolution that fits into video memory!!\n");
+	    return -EINVAL;
+	}
+	_par->var.xres_virtual = modes[i].xres;
+	_par->var.yres_virtual = modes[i].yres;
+
+	printk("clgen: virtual resolution set to maximum of %dx%d\n",
+		_par->var.xres_virtual, _par->var.yres_virtual);
+    }
+    else if (_par->var.xres_virtual == -1)
+    {
+    }
+    else if (_par->var.yres_virtual == -1)
+    {
+    }
+
+    if (_par->var.xoffset < 0) _par->var.xoffset = 0;
+    if (_par->var.yoffset < 0) _par->var.yoffset = 0;
+	
+    /* truncate xoffset and yoffset to maximum if too high */
+    if (_par->var.xoffset > _par->var.xres_virtual-_par->var.xres)
+	_par->var.xoffset = _par->var.xres_virtual-_par->var.xres -1;
+
+    if (_par->var.yoffset > _par->var.yres_virtual-_par->var.yres)
+	_par->var.yoffset = _par->var.yres_virtual-_par->var.yres -1;
+
+    switch (var->bits_per_pixel)
+    {
+    case 1:
+	_par->line_length	= _par->var.xres_virtual / 8;
+	_par->visual		= FB_VISUAL_MONO10;
+	break;
+
+    case 8:
+	_par->line_length 	= _par->var.xres_virtual;
+	_par->visual		= FB_VISUAL_PSEUDOCOLOR;
+	break;
+
+    case 16:
+	_par->line_length	= _par->var.xres_virtual * 2;
+	_par->visual		= FB_VISUAL_DIRECTCOLOR;
+	break;
+
+    case 24:
+	_par->line_length	= _par->var.xres_virtual * 3;
+	_par->visual		= FB_VISUAL_DIRECTCOLOR;
+	break;
+
+    case 32:
+	_par->line_length	= _par->var.xres_virtual * 4;
+	_par->visual		= FB_VISUAL_DIRECTCOLOR;
+	break;
+    }
+    _par->type		= FB_TYPE_PACKED_PIXELS;
+
+    /* convert from ps to kHz */
+    freq = 1000000000 / var->pixclock;
+
+    DEBUG printk("desired pixclock: %ld kHz\n", freq);	
+
+    /* the SD64/P4 have a higher max. videoclock */
+    bestclock(freq, &_par->freq, &_par->nom, &_par->den, &_par->div, 
+		fb_info->btype == BT_SD64 || fb_info->btype == BT_PICASSO4
+		? 140000 : 90000);
+
+    DEBUG printk("Best possible values for given frequency: best: %ld kHz  nom: %ld  den: %ld  div: %ld\n", 
+		 _par->freq, _par->nom, _par->den, _par->div);
+
+    xres   = _par->var.xres;
+    hfront = _par->var.right_margin;
+    hsync  = _par->var.hsync_len;
+    hback  = _par->var.left_margin;
+
+    yres   = _par->var.yres;
+    vfront = _par->var.lower_margin;
+    vsync  = _par->var.vsync_len;
+    vback  = _par->var.upper_margin;
+    
+    if (_par->var.vmode & FB_VMODE_DOUBLE)
+    {
+    	yres   *= 2;
+    	vfront *= 2;
+    	vsync  *= 2;
+    	vback  *= 2;
+    }
+    else if (_par->var.vmode & FB_VMODE_INTERLACED)
+    {
+    	yres   = ++yres   / 2;
+    	vfront = ++vfront / 2;
+    	vsync  = ++vsync  / 2;
+    	vback  = ++vback  / 2;
+    }
+
+    _par->HorizRes        = xres;
+    _par->HorizTotal      = (xres + hfront + hsync + hback)/8 - 5;
+    _par->HorizDispEnd    = xres/8 - 1;
+    _par->HorizBlankStart = xres/8;
+    _par->HorizBlankEnd   = _par->HorizTotal+5; /* does not count with "-5" */
+    _par->HorizSyncStart  = (xres + hfront)/8 + 1;
+    _par->HorizSyncEnd    = (xres + hfront + hsync)/8 + 1;
+
+    _par->VertRes         = yres;
+    _par->VertTotal       = yres + vfront + vsync + vback -2;
+    _par->VertDispEnd     = yres - 1;
+    _par->VertBlankStart  = yres;
+    _par->VertBlankEnd    = _par->VertTotal;
+    _par->VertSyncStart   = yres + vfront - 1;
+    _par->VertSyncEnd     = yres + vfront + vsync - 1;
+
+    if (_par->VertTotal >= 1024)
+    {
+	printk(KERN_WARNING "clgen: ERROR: VerticalTotal >= 1024; special treatment required! (TODO)\n");
+	return -EINVAL;
+    }
+
+    return 0;
+}
+
+
+static int clgen_encode_var(struct fb_var_screeninfo *var, const void *par,
+			    struct fb_info_gen *info)
+{
+    *var = ((struct clgenfb_par*)par)->var;
+    return 0;
+}
+
+/* get current video mode */
+static void clgen_get_par(void *par, struct fb_info_gen *info)
+{
+    struct clgenfb_par *_par  = (struct clgenfb_par*)par;
+    struct clgenfb_info*_info = (struct clgenfb_info*)fb_info;
+
+    *_par = _info->currentmode;   
+}
+
+/*************************************************************************
+	clgen_set_par()
+
+	actually writes the values for a new video mode into the hardware,
+**************************************************************************/
+static void clgen_set_par(const void *par, struct fb_info_gen *info)
+{
+    unsigned char tmp;
+    int offset = 0;
+    struct clgenfb_par *_par = (struct clgenfb_par*)par;
+
+    printk(KERN_INFO">clgen_set_par()\n");
+    printk(KERN_INFO"Requested mode: %dx%dx%d\n",
+		    _par->var.xres, _par->var.yres, _par->var.bits_per_pixel);
+    printk(KERN_INFO"pixclock: %d\n", _par->var.pixclock);
+    
+    fb_info = (struct clgenfb_info *)info;
+
+    /* unlock register CRT0..CRT7 */
+    WCrt(CRT11, 0x20); /* previously: 0x00) */
+
+    /* if DEBUG is set, all parameters get output before writing */
+    DEBUG printk("CRT0: %ld\n", _par->HorizTotal); 
+    WCrt(CRT0, _par->HorizTotal);
+
+    DEBUG printk("CRT1: %ld\n", _par->HorizDispEnd); 
+    WCrt(CRT1, _par->HorizDispEnd);
+
+    DEBUG printk("CRT2: %ld\n", _par->HorizBlankStart); 
+    WCrt(CRT2, _par->HorizBlankStart);
+
+    DEBUG printk("CRT3: 128+%ld\n", _par->HorizBlankEnd % 32); /*  + 128: Compatible read */
+    WCrt(CRT3, 128 + (_par->HorizBlankEnd % 32));
+
+    DEBUG printk("CRT4: %ld\n", _par->HorizSyncStart);
+    WCrt(CRT4, _par->HorizSyncStart);
+
+    tmp = _par->HorizSyncEnd % 32;
+    if (_par->HorizBlankEnd & 32)	
+    	tmp += 128;
+    DEBUG printk("CRT5: %d\n", tmp); 
+    WCrt(CRT5, tmp);
+
+    DEBUG printk("CRT6: %ld\n", _par->VertTotal & 0xff); 
+    WCrt(CRT6, (_par->VertTotal & 0xff));
+
+    tmp = 16;  /* LineCompare bit #9 */
+    if (_par->VertTotal      & 256) tmp |= 1;
+    if (_par->VertDispEnd    & 256) tmp |= 2;
+    if (_par->VertSyncStart  & 256) tmp |= 4;
+    if (_par->VertBlankStart & 256) tmp |= 8;
+    if (_par->VertTotal      & 512) tmp |= 32;
+    if (_par->VertDispEnd    & 512) tmp |= 64;
+    if (_par->VertSyncStart  & 512) tmp |= 128;
+    DEBUG printk("CRT7: %d\n", tmp);
+    WCrt(CRT7, tmp);
+
+    tmp = 0x40; /* LineCompare bit #8 */
+    if (_par->VertBlankStart & 512)		tmp |= 0x20;
+    if (_par->var.vmode & FB_VMODE_DOUBLE)	tmp |= 0x80;
+    DEBUG printk("CRT9: %d\n", tmp);
+    WCrt(CRT9, tmp);
+
+    DEBUG printk("CRT10: %ld\n", _par->VertSyncStart & 0xff);
+    WCrt(CRT10, (_par->VertSyncStart & 0xff));
+
+    DEBUG printk("CRT11: 64+32+%ld\n", _par->VertSyncEnd % 16);
+    WCrt(CRT11, (_par->VertSyncEnd % 16 + 64 + 32));
+
+    DEBUG printk("CRT12: %ld\n", _par->VertDispEnd & 0xff);
+    WCrt(CRT12, (_par->VertDispEnd & 0xff));
+
+    DEBUG printk("CRT15: %ld\n", _par->VertBlankStart & 0xff);
+    WCrt(CRT15, (_par->VertBlankStart & 0xff));
+
+    DEBUG printk("CRT16: %ld\n", _par->VertBlankEnd & 0xff);
+    WCrt(CRT16, (_par->VertBlankEnd & 0xff));
+
+    DEBUG printk("CRT18: 0xff\n");
+    WCrt(CRT18, 0xff);
+
+    tmp = 0;
+    if (_par->var.vmode & FB_VMODE_INTERLACED)	tmp |= 1;
+    if (_par->HorizBlankEnd & 64)		tmp |= 16;
+    if (_par->HorizBlankEnd & 128)		tmp |= 32;
+    if (_par->VertBlankEnd  & 256)		tmp |= 64;
+    if (_par->VertBlankEnd  & 512)		tmp |= 128;
+    
+    DEBUG printk("CRT1a: %d\n", tmp);
+    WCrt(CRT1A, tmp);
+
+    /* set VCLK0 */
+    /* hardware RefClock: 14.31818 MHz */
+    /* formula: VClk = (OSC * N) / (D * (1+P)) */
+    /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
+
+    WSeq(SEQRB, _par->nom);
+    tmp = _par->den<<1; 
+    if (_par->div != 0) tmp |= 1;
+
+    if (fb_info->btype == BT_SD64)
+    	tmp |= 0x80; /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
+    
+    WSeq(SEQR1B, tmp);
+
+    WCrt(CRT17, 0xc3); /* mode control: CRTC enable, ROTATE(?), 16bit address wrap, no compat. */
+
+/* HAEH?	WCrt(CRT11, 0x20);  * previously: 0x00  unlock CRT0..CRT7 */
+
+    /* don't know if it would hurt to also program this if no interlaced */
+    /* mode is used, but I feel better this way.. :-) */
+    if (_par->var.vmode & FB_VMODE_INTERLACED)
+    	WCrt(CRT19, _par->HorizTotal / 2);
+    else
+    	WCrt(CRT19, 0x00);	/* interlace control */
+
+    WSeq(SEQR3, 0);
+
+    /* adjust horizontal/vertical sync type (low/high) */
+    tmp = 0x03; /* enable display memory & CRTC I/O address for color mode */
+    if (_par->var.sync & FB_SYNC_HOR_HIGH_ACT)  tmp |= 0x40;
+    if (_par->var.sync & FB_SYNC_VERT_HIGH_ACT) tmp |= 0x80;
+    WGen(MISC_W, tmp);
+
+    WCrt(CRT8,    0);      /* Screen A Preset Row-Scan register */
+    WCrt(CRTA,    0);      /* text cursor on and start line */
+    WCrt(CRTB,   31);      /* text cursor end line */
+
+    /* programming for different color depths */
+    if (_par->var.bits_per_pixel == 1)
+    {
+	DEBUG printk(KERN_INFO "clgen: preparing for 1 bit deep display\n");
+#if 0
+    	/* restore first 2 color registers for mono mode */
+    	WClut( 0, 0x00, 0x00, 0x00);  /* background: black */
+	WClut( 1, 0xff, 0xff, 0xff);  /* foreground: white */
+#endif
+	WGfx(GR5,     0);      /* mode register */
+	
+	/* Extended Sequencer Mode */
+	switch(fb_info->btype)
+	{
+	case BT_SD64:
+	    /* setting the SEQRF on SD64 is not necessary (only during init) */
+	    DEBUG printk(KERN_INFO "(for SD64)\n");
+	    WSeq(SEQR7,  0xf0);
+	    WSeq(SEQR1F, 0x1a);     /*  MCLK select */
+	    break;
+
+	case BT_PICCOLO:
+	    DEBUG printk(KERN_INFO "(for Piccolo)\n");
+	    WSeq(SEQR7, 0x80);
+/* ### ueberall 0x22? */
+	    WSeq(SEQR1F, 0x22);     /* ##vorher 1c MCLK select */
+	    WSeq(SEQRF, 0xb0);    /* evtl d0 bei 1 bit? avoid FIFO underruns..? */
+	    break;
+
+	case BT_PICASSO:
+	    DEBUG printk(KERN_INFO "(for Picasso)\n");
+	    WSeq(SEQR7, 0x20);
+	    WSeq(SEQR1F, 0x22);     /* ##vorher 22 MCLK select */
+	    WSeq(SEQRF, 0xd0);    /* ## vorher d0 avoid FIFO underruns..? */
+	    break;
+
+	case BT_SPECTRUM:
+	    DEBUG printk(KERN_INFO "(for Spectrum)\n");
+	    WSeq(SEQR7, 0x80);
+/* ### ueberall 0x22? */
+	    WSeq(SEQR1F, 0x22);     /* ##vorher 1c MCLK select */
+	    WSeq(SEQRF, 0xb0);    /* evtl d0? avoid FIFO underruns..? */
+	    break;
+
+	case BT_PICASSO4:
+	    DEBUG printk(KERN_INFO "(for Picasso 4)\n");
+	    WSeq(SEQR7, 0x20);
+/*	    WSeq(SEQR1F, 0x1c); */
+/* SEQRF not being set here...	WSeq(SEQRF, 0xd0); */
+	    break;
+
+	default:
+	    printk(KERN_WARNING "clgen: unknown Board\n");
+	    break;
+	}
+
+	WGen(M_3C6,0x01);     /* pixel mask: pass-through for first plane */
+	WHDR(0);              /* hidden dac reg: nothing special */
+	WSeq(SEQR4,  0x06);     /* memory mode: odd/even, ext. memory */
+	WSeq(SEQR2, 0x01);      /* plane mask: only write to first plane */
+	offset 			= _par->var.xres_virtual / 16;
+    }
+    else if (_par->var.bits_per_pixel == 8)
+    {
+	DEBUG printk(KERN_INFO "clgen: preparing for 8 bit deep display\n");
+	switch(fb_info->btype)
+	{
+	case BT_SD64:
+	    WSeq(SEQR7,  0xf1); /* Extended Sequencer Mode: 256c col. mode */
+	    WSeq(SEQR1F, 0x1d);     /* MCLK select */
+	    break;
+
+	case BT_PICCOLO:
+	    WSeq(SEQR7, 0x81);
+	    WSeq(SEQR1F, 0x22);     /* ### vorher 1c MCLK select */
+	    WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+	    break;
+
+	case BT_PICASSO:
+	    WSeq(SEQR7, 0x21);
+	    WSeq(SEQR1F, 0x22);     /* ### vorher 1c MCLK select */
+	    WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+	    break;
+
+	case BT_SPECTRUM:
+	    WSeq(SEQR7, 0x81);
+	    WSeq(SEQR1F, 0x22);     /* ### vorher 1c MCLK select */
+	    WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+	    break;
+
+	case BT_PICASSO4:
+	    WSeq(SEQR7, 0x21);
+	    WSeq(SEQRF, 0xb8); /* ### INCOMPLETE!! */
+/*	    WSeq(SEQR1F, 0x1c); */
+	    break;
+
+	default:
+	    printk(KERN_WARNING "clgen: unknown Board\n");
+	    break;
+	}
+
+	WGfx(GR5,    64);     /* mode register: 256 color mode */
+	WGen(M_3C6,0xff);     /* pixel mask: pass-through all planes */
+	WHDR(0);              /* hidden dac reg: nothing special */
+	WSeq(SEQR4,  0x0a);     /* memory mode: chain4, ext. memory */
+	WSeq(SEQR2,  0xff);     /* plane mask: enable writing to all 4 planes */
+	offset 			= _par->var.xres_virtual / 8;
+    }
+    else if (_par->var.bits_per_pixel == 16)
+    {
+	DEBUG printk(KERN_INFO "clgen: preparing for 16 bit deep display\n");
+	switch(fb_info->btype)
+	{
+	case BT_SD64:
+	    WSeq(SEQR7,  0xf7); /* Extended Sequencer Mode: 256c col. mode */
+	    WSeq(SEQR1F, 0x1e);     /* MCLK select */
+	    break;
+
+	case BT_PICCOLO:
+	    WSeq(SEQR7, 0x87);
+	    WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+	    WSeq(SEQR1F, 0x22);     /* MCLK select */
+	    break;
+
+	case BT_PICASSO:
+	    WSeq(SEQR7, 0x27);
+	    WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+	    WSeq(SEQR1F, 0x22);     /* MCLK select */
+	    break;
+
+	case BT_SPECTRUM:
+	    WSeq(SEQR7, 0x87);
+	    WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+	    WSeq(SEQR1F, 0x22);     /* MCLK select */
+	    break;
+
+	case BT_PICASSO4:
+	    WSeq(SEQR7, 0x27);
+/*	    WSeq(SEQR1F, 0x1c);  */
+	    break;
+
+	default:
+	    printk(KERN_WARNING "CLGEN: unknown Board\n");
+	    break;
+	}
+
+	WGfx(GR5,    64);     /* mode register: 256 color mode */
+	WGen(M_3C6,0xff);     /* pixel mask: pass-through all planes */
+	WHDR(0xa0);           /* hidden dac reg: nothing special */
+	WSeq(SEQR4,  0x0a);     /* memory mode: chain4, ext. memory */
+	WSeq(SEQR2,  0xff);     /* plane mask: enable writing to all 4 planes */
+	offset 			= _par->var.xres_virtual / 4;
+    }
+    else if (_par->var.bits_per_pixel == 32)
+    {
+	DEBUG printk(KERN_INFO "clgen: preparing for 24/32 bit deep display\n");
+	switch(fb_info->btype)
+	{
+	case BT_SD64:
+	    WSeq(SEQR7,  0xf9); /* Extended Sequencer Mode: 256c col. mode */
+	    WSeq(SEQR1F, 0x1e);     /* MCLK select */
+	    break;
+
+	case BT_PICCOLO:
+	    WSeq(SEQR7, 0x85);
+	    WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+	    WSeq(SEQR1F, 0x22);     /* MCLK select */
+	    break;
+
+	case BT_PICASSO:
+	    WSeq(SEQR7, 0x25);
+	    WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+	    WSeq(SEQR1F, 0x22);     /* MCLK select */
+	    break;
+
+	case BT_SPECTRUM:
+	    WSeq(SEQR7, 0x85);
+	    WSeq(SEQRF, 0xb0);    /* Fast Page-Mode writes */
+	    WSeq(SEQR1F, 0x22);     /* MCLK select */
+	    break;
+
+	case BT_PICASSO4:
+	    WSeq(SEQR7, 0x25);
+/*	    WSeq(SEQR1F, 0x1c);  */
+	    break;
+
+	default:
+	    printk(KERN_WARNING "clgen: unknown Board\n");
+	    break;
+	}
+
+	WGfx(GR5,    64);     /* mode register: 256 color mode */
+	WGen(M_3C6,0xff);     /* pixel mask: pass-through all planes */
+	WHDR(0xc5);           /* hidden dac reg: 8-8-8 mode (24 or 32) */
+	WSeq(SEQR4,  0x0a);     /* memory mode: chain4, ext. memory */
+	WSeq(SEQR2,  0xff);     /* plane mask: enable writing to all 4 planes */
+	offset			= _par->var.xres_virtual / 4;
+    }
+    else
+	printk(KERN_ERR "clgen: What's this?? requested color depth == %d.\n",
+		_par->var.bits_per_pixel);
+
+    WCrt(CRT13, offset & 0xff);
+    tmp = 0x22;
+    if (offset & 0x100) tmp |= 0x10; /* offset overflow bit */
+    	
+    WCrt(CRT1B,tmp);    /* screen start addr #16-18, fastpagemode cycles */
+
+    if (fb_info->btype == BT_SD64 || fb_info->btype == BT_PICASSO4)
+    	WCrt(CRT1D, 0x00);   /* screen start address bit 19 */
+
+    WCrt(CRTE,    0);      /* text cursor location high */
+    WCrt(CRTF,    0);      /* text cursor location low */
+    WCrt(CRT14,   0);      /* underline row scanline = at very bottom */
+
+    WAttr(AR10,  1);      /* controller mode */
+    WAttr(AR11,  0);      /* overscan (border) color */
+    WAttr(AR12, 15);      /* color plane enable */
+    WAttr(AR33,  0);      /* pixel panning */
+    WAttr(AR14,  0);      /* color select */
+
+    /* [ EGS: SetOffset(); ] */
+    /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
+    AttrOn();
+
+    WGfx(GR0,    0);      /* set/reset register */
+    WGfx(GR1,    0);      /* set/reset enable */
+    WGfx(GR2,    0);      /* color compare */
+    WGfx(GR3,    0);      /* data rotate */
+    WGfx(GR4,    0);      /* read map select */
+    WGfx(GR6,    1);      /* miscellaneous register */
+    WGfx(GR7,   15);      /* color don't care */
+    WGfx(GR8,  255);      /* bit mask */
+
+    WSeq(SEQR12,  0x0);     /* graphics cursor attributes: nothing special */
+
+    /* finally, turn on everything - turn off "FullBandwidth" bit */
+    /* also, set "DotClock%2" bit where requested */
+    tmp = 0x01;
+
+/*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
+    if (var->vmode & FB_VMODE_CLOCK_HALVE)
+	tmp |= 0x08;
+*/
+
+    WSeq(SEQR1, tmp);
+    DEBUG printk("SEQR1: %d\n", tmp);
+
+#if 0
+    DEBUG printk(KERN_INFO "clgen: clearing display...");
+    clgen_RectFill(0, 0, _par->HorizRes, _par->VertRes, 0, _par->line_length);
+    clgen_WaitBLT();
+    DEBUG printk("done.\n");
+#endif
+
+    fb_info->currentmode = *_par;
+
+    printk("virtual offset: (%d,%d)\n", _par->var.xoffset,_par->var.yoffset);
+    /* pan to requested offset */
+    clgen_pan_display (&fb_info->currentmode.var, (struct fb_info_gen*)fb_info);
+
+    DEBUG printk("<clgen_set_par()\n");
+    return;
+}
+
+static int clgen_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			   unsigned *blue, unsigned *transp,
+			   struct fb_info *info)
+{
+    unsigned char bred, bgreen, bblue;
+
+    if (regno > 255 || regno < 0)
+	return (1);
+
+    fb_info = (struct clgenfb_info *)info;
+
+    RClut(regno, &bred, &bgreen, &bblue);
+
+    *red    = (u_int)bred;
+    *green  = (u_int)bgreen;
+    *blue   = (u_int)bblue;
+    *transp = 0;
+    return (0);
+}
+
+static int clgen_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp, 
+			   struct fb_info *info)
+{
+    if (regno > 255 || regno < 0)
+	return (1);
+
+    fb_info = (struct clgenfb_info *)info;
+    
+    /* "transparent" stuff is completely ignored. */
+    WClut(regno, (red & 0xff), (green & 0xff), (blue & 0xff));
+
+    return (0);
+}
+
+/*************************************************************************
+	clgen_pan_display()
+
+	performs display panning - provided hardware permits this
+**************************************************************************/
+static int clgen_pan_display(const struct fb_var_screeninfo *var,
+			     struct fb_info_gen *info)
+{
+    int xoffset = 0;
+    int yoffset = 0;
+    unsigned long base;
+    unsigned char tmp = 0, tmp2 = 0, xpix;
+
+    fb_info = (struct clgenfb_info*)fb_info;
+
+    /* no range checks for xoffset and yoffset,   */
+    /* as fbgen_pan_display has already done this */
+
+    fb_info->currentmode.var.xoffset = var->xoffset;
+    fb_info->currentmode.var.yoffset = var->yoffset;
+
+    xoffset = var->xoffset * fb_info->currentmode.var.bits_per_pixel / 8;
+    yoffset = var->yoffset;
+
+    base = yoffset * fb_info->currentmode.line_length + xoffset;
+
+    if (fb_info->currentmode.var.bits_per_pixel == 1)
+    {
+	/* base is already correct */
+	xpix = (unsigned char)(var->xoffset % 8);
+    }
+    else
+    {
+	base /= 4;
+	xpix = (unsigned char)((xoffset % 4) * 2);
+    }
+
+    /* lower 8 + 8 bits of screen start address */
+    WCrt(CRTD, (unsigned char)(base & 0xff));
+    WCrt(CRTC, (unsigned char)(base >> 8));
+
+    /* construct bits 16, 17 and 18 of screen start address */
+    if (base & 0x10000) tmp |= 0x01;
+    if (base & 0x20000) tmp |= 0x04;
+    if (base & 0x40000) tmp |= 0x08;
+
+    tmp2 = (RCrt(CRT1B) & 0xf2) | tmp; /* 0xf2 is %11110010, exclude tmp bits */
+    WCrt(CRT1B, tmp2);
+    /* construct bit 19 of screen start address (only on SD64) */
+    if (fb_info->btype == BT_SD64 ||
+	fb_info->btype == BT_PICASSO4)
+    {
+	tmp2 = 0;
+	if (base & 0x80000) tmp2 = 0x80;
+	WCrt(CRT1D, tmp2);
+    }
+
+    /* write pixel panning value to AR33; this does not quite work in 8bpp */
+    /* ### Piccolo..? Will this work? */
+    if (fb_info->currentmode.var.bits_per_pixel == 1)
+	WAttr(AR33, xpix);
+
+    return(0);
+}
+
+
+static int clgen_blank(int blank_mode, struct fb_info_gen *info)
+{
+    unsigned char val;
+    printk(">clgen_blank(%d)\n",blank_mode);
+
+    fb_info = (struct clgenfb_info *)info;
+
+    val = RSeq(SEQR1);
+    if (blank_mode)
+	WSeq(SEQR1, val | 0x20); /* set "FullBandwidth" bit */
+    else
+	WSeq(SEQR1, val & 0xdf); /* clear "FullBandwidth" bit */
+
+    printk("<clgen_blank()\n");
+    return 0;
+}
+
+/**** END   Hardware specific Routines **************************************/
+/****************************************************************************/
+/**** BEGIN Internal Routines ***********************************************/
+
+static void init_vgachip(void)
+{
+    printk(">init_vgachip()\n");
+
+    /* reset board globally */
+    switch(fb_info->btype)
+    {
+    case BT_SD64:     WSFR(0x1f);  udelay(500); WSFR(0x4f); udelay(500); break;
+    case BT_PICCOLO:  WSFR(0x01);  udelay(500); WSFR(0x51); udelay(500); break;
+    case BT_PICASSO:  WSFR2(0xff); udelay(500);				 break;
+    case BT_SPECTRUM: WSFR(0x1f);  udelay(500); WSFR(0x4f); udelay(500); break;
+    case BT_PICASSO4: 
+	WCrt(CRT51, 0x00); /* disable flickerfixer */
+	udelay(100000);
+	WGfx(GR2F, 0x00); /* from Klaus' NetBSD driver: */
+	WGfx(GR33, 0x00); /* put blitter into 542x compat */
+	WGfx(GR31, 0x00); /* mode */
+	break;
+
+    default:
+	printk(KERN_ERR "clgen: Warning: Unknown board type\n");
+	break;
+    }
+
+    /* "pre-set" a RAMsize; if the test succeeds, double it */
+    if (fb_info->btype == BT_SD64 ||
+        fb_info->btype == BT_PICASSO4)
+        fb_info->size = 0x400000;
+    else
+        fb_info->size = 0x200000;
+
+    /* assume it's a "large memory" board (2/4 MB) */
+    fb_info->smallboard = FALSE;
+
+    /* the P4 is not fully initialized here; I rely on it having been */
+    /* inited under AmigaOS already, which seems to work just fine    */
+    /* (Klaus advised to do it this way)                              */
+
+    if (fb_info->btype != BT_PICASSO4)
+    {
+	WGen(VSSM, 0x10);  /* EGS: 0x16 */
+	WGen(POS102, 0x01);
+	WGen(VSSM, 0x08);  /* EGS: 0x0e */
+
+	if(fb_info->btype != BT_SD64)
+		WGen(VSSM2, 0x01);
+
+	WSeq(SEQR0, 0x03);  /* reset sequencer logic */
+
+	WSeq(SEQR1, 0x21);  /* FullBandwidth (video off) and 8/9 dot clock */
+	WGen(MISC_W, 0xc1);  /* polarity (-/-), disable access to display memory, CRTC base address: color */
+
+/*	WGfx(GRA, 0xce);    "magic cookie" - doesn't make any sense to me.. */
+	WSeq(SEQR6, 0x12);   /* unlock all extension registers */
+
+	WGfx(GR31, 0x04);  /* reset blitter */
+
+	if (fb_info->btype == BT_SD64)
+	{
+	    WSeq(SEQRF, 0xb8);  /* 4 MB Ram SD64, disable CRT fifo(!), 64 bit bus */
+	}
+	else
+	{
+	    WSeq(SEQR16, 0x0f); /* Perf. Tuning: Fix value..(?) */
+	    WSeq(SEQRF, 0xb0); /* 2 MB DRAM, 8level write buffer, 32bit bus */
+	}
+    }
+
+    WSeq(SEQR2, 0xff);  /* plane mask: nothing */
+    WSeq(SEQR3, 0x00);  /* character map select: doesn't even matter in gx mode */
+    WSeq(SEQR4, 0x0e);  /* memory mode: chain-4, no odd/even, ext. memory */
+
+    /* controller-internal base address of video memory */
+    switch(fb_info->btype)
+    {
+    case BT_SD64:     WSeq(SEQR7, 0xf0); break;
+    case BT_PICCOLO:  WSeq(SEQR7, 0x80); break;
+    case BT_SPECTRUM: WSeq(SEQR7, 0x80); break;
+    case BT_PICASSO:  WSeq(SEQR7, 0x20); break;
+    case BT_PICASSO4: WSeq(SEQR7, 0x20); break;
+    }
+
+/*  WSeq(SEQR8, 0x00);*/  /* EEPROM control: shouldn't be necessary to write to this at all.. */
+
+    WSeq(SEQR10, 0x00); /* graphics cursor X position (incomplete; position gives rem. 3 bits */
+    WSeq(SEQR11, 0x00); /* graphics cursor Y position (..."... ) */
+    WSeq(SEQR12, 0x00); /* graphics cursor attributes */
+    WSeq(SEQR13, 0x00); /* graphics cursor pattern address */
+
+    /* writing these on a P4 might give problems..  */
+    if (fb_info->btype != BT_PICASSO4)
+    {
+	WSeq(SEQR17, 0x00); /* configuration readback and ext. color */
+	WSeq(SEQR18, 0x02); /* signature generator */
+    }
+
+    /* MCLK select etc. */
+    switch(fb_info->btype)
+    {
+    case BT_PICCOLO:
+    case BT_PICASSO:
+    case BT_SPECTRUM:  WSeq(SEQR1F, 0x22); break;
+    case BT_SD64:      WSeq(SEQR1F, 0x20); break;
+    case BT_PICASSO4:/*WSeq(SEQR1F, 0x1c); */ break;
+    }
+
+    WCrt(CRT8, 0x00);  /* Screen A preset row scan: none */
+    WCrt(CRTA, 0x20);  /* Text cursor start: disable text cursor */
+    WCrt(CRTB, 0x00);  /* Text cursor end: - */
+    WCrt(CRTC, 0x00);  /* Screen start address high: 0 */
+    WCrt(CRTD, 0x00);  /* Screen start address low: 0 */
+    WCrt(CRTE, 0x00);  /* text cursor location high: 0 */
+    WCrt(CRTF, 0x00);  /* text cursor location low: 0 */
+
+    WCrt(CRT14, 0x00); /* Underline Row scanline: - */
+    WCrt(CRT17, 0xc3); /* mode control: timing enable, byte mode, no compat modes */
+    WCrt(CRT18, 0x00); /* Line Compare: not needed */
+    /* ### add 0x40 for text modes with > 30 MHz pixclock */
+    WCrt(CRT1B, 0x02); /* ext. display controls: ext.adr. wrap */
+
+    WGfx(GR0, 0x00); /* Set/Reset registes: - */
+    WGfx(GR1, 0x00); /* Set/Reset enable: - */
+    WGfx(GR2, 0x00); /* Color Compare: - */
+    WGfx(GR3, 0x00); /* Data Rotate: - */
+    WGfx(GR4, 0x00); /* Read Map Select: - */
+    WGfx(GR5, 0x00); /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
+    WGfx(GR6, 0x01); /* Miscellaneous: memory map base address, graphics mode */
+    WGfx(GR7, 0x0f); /* Color Don't care: involve all planes */
+    WGfx(GR8, 0xff); /* Bit Mask: no mask at all */
+    WGfx(GRB, 0x28); /* Graphics controller mode extensions: finer granularity, 8byte data latches */
+
+    WGfx(GRC, 0xff); /* Color Key compare: - */
+    WGfx(GRD, 0x00); /* Color Key compare mask: - */
+    WGfx(GRE, 0x00); /* Miscellaneous control: - */
+/*  WGfx(GR10, 0x00);*/ /* Background color byte 1: - */
+/*  WGfx(GR11, 0x00); */
+
+    WAttr(AR0, 0x00); /* Attribute Controller palette registers: "identity mapping" */
+    WAttr(AR1, 0x01);
+    WAttr(AR2, 0x02);
+    WAttr(AR3, 0x03);
+    WAttr(AR4, 0x04);
+    WAttr(AR5, 0x05);
+    WAttr(AR6, 0x06);
+    WAttr(AR7, 0x07);
+    WAttr(AR8, 0x08);
+    WAttr(AR9, 0x09);
+    WAttr(ARA, 0x0a);
+    WAttr(ARB, 0x0b);
+    WAttr(ARC, 0x0c);
+    WAttr(ARD, 0x0d);
+    WAttr(ARE, 0x0e);
+    WAttr(ARF, 0x0f);
+
+    WAttr(AR10, 0x01); /* Attribute Controller mode: graphics mode */
+    WAttr(AR11, 0x00); /* Overscan color reg.: reg. 0 */
+    WAttr(AR12, 0x0f); /* Color Plane enable: Enable all 4 planes */
+/* ### 	WAttr(AR33, 0x00); * Pixel Panning: - */
+    WAttr(AR14, 0x00); /* Color Select: - */
+
+    WGen(M_3C6, 0xff); /* Pixel mask: no mask */
+
+    WGen(MISC_W, 0xc3); /* polarity (-/-), enable display mem, CRTC i/o base = color */
+
+    WGfx(GR31, 0x04); /* BLT Start/status: Blitter reset */
+    WGfx(GR31, 0x00); /* - " -           : "end-of-reset" */
+
+    /* CLUT setup */
+    WClut( 0, 0x00, 0x00, 0x00);  /* background: black */
+    WClut( 1, 0xff, 0xff, 0xff);  /* foreground: white */
+    WClut( 2, 0x00, 0x80, 0x00);
+    WClut( 3, 0x00, 0x80, 0x80);
+    WClut( 4, 0x80, 0x00, 0x00);
+    WClut( 5, 0x80, 0x00, 0x80);
+    WClut( 6, 0x80, 0x40, 0x00);
+    WClut( 7, 0x80, 0x80, 0x80);
+    WClut( 8, 0x40, 0x40, 0x40);
+    WClut( 9, 0x40, 0x40, 0xc0);
+    WClut(10, 0x40, 0xc0, 0x40);
+    WClut(11, 0x40, 0xc0, 0xc0);
+    WClut(12, 0xc0, 0x40, 0x40);
+    WClut(13, 0xc0, 0x40, 0xc0);
+    WClut(14, 0xc0, 0xc0, 0x40);
+    WClut(15, 0xc0, 0xc0, 0xc0);
+
+    /* the rest a grey ramp */
+    {
+	int i;
+
+	for (i = 16; i < 256; i++)
+	    WClut(i, i, i, i);
+    }
+
+
+    /* misc... */
+    WHDR(0); /* Hidden DAC register: - */
+
+#if 0
+    /* check for 1/2 MB Piccolo/Picasso/Spectrum resp. 2/4 MB SD64 */
+    /* DRAM register has already been pre-set for "large", so it is*/
+    /* only modified if we find that this is a "small" version */
+    {
+	unsigned volatile char *ram = fb_info->fbmem;
+	int i, flag = 0;
+
+	ram += (fb_info->size >> 1);
+
+	for (i = 0; i < 256; i++)
+	    ram[i] = (unsigned char)i;
+
+	for (i = 0; i < 256; i++)
+	{
+	    if (ram[i] != i)
+		flag = 1;
+	}
+
+	/* if the DRAM test failed, halve RAM value */
+	if (flag)
+	{
+	    fb_info->size /= 2;
+	    fb_info->smallboard = TRUE;
+	    switch(fb_info->btype)
+	    {
+	    case BT_SD64:     WSeq(SEQRF, 0x38); break; /* 2 MB Ram SD64 */
+	    case BT_PICASSO4: WSeq(SEQRF, 0x38); break; /* ### like SD64? */
+	    case BT_PICCOLO:
+	    case BT_PICASSO:
+	    case BT_SPECTRUM: WSeq(SEQRF, 0x30); break; /* 1 MB DRAM */
+	    default:
+		printk(KERN_WARNING "clgen: Uuhh..could not determine RAM size!\n");
+	    }
+	}
+
+    }
+#endif
+    printk(KERN_INFO "clgen: This board has %ld bytes of DRAM memory\n", fb_info->size);
+    printk("<init_vgachip()\n");
+    return;
+}
+
+static void switch_monitor(int on)
+{
+    static int IsOn = 0;    /* XXX not ok for multiple boards */
+
+    if (fb_info->btype == BT_PICASSO4) return; /* nothing to switch */
+    if (fb_info->btype == BT_PICASSO)
+    {
+	if ((on && !IsOn) || (!on && IsOn))
+	    WSFR(0xff);
+	return;
+    }    
+    if (on)
+        switch(fb_info->btype)
+	{
+        case BT_SD64:     WSFR(fb_info->SFR | 0x21);	break;
+        case BT_PICCOLO:  WSFR(fb_info->SFR | 0x28);	break;
+        case BT_SPECTRUM: WSFR(0x6f);			break;
+	}
+    else
+        switch(fb_info->btype)
+	{
+        case BT_SD64:     WSFR(fb_info->SFR & 0xde);	break;
+        case BT_PICCOLO:  WSFR(fb_info->SFR & 0xd7);	break;
+        case BT_SPECTRUM: WSFR(0x4f);			break;
+	}
+}
+
+static struct display_switch *clgen_get_dispsw(const void *par,
+					     struct fb_info_gen *info)
+{
+    struct clgenfb_par *_par = (struct clgenfb_par*) par;
+
+    printk("clgen_get_dispsw(): ");
+    switch (_par->var.bits_per_pixel)
+    {
+#ifdef FBCON_HAS_MFB
+    case 1:
+	printk("monochrome\n");
+	return &fbcon_mfb;
+#endif
+#ifdef FBCON_HAS_CFB8
+    case 8:
+	printk("8 bit color depth\n");
+	return &fbcon_clgen_8;
+#endif
+#ifdef FBCON_HAS_CFB16
+    case 16:
+	printk("16 bit color depth\n");
+	return &fbcon_cfb16;
+#endif
+#ifdef FBCON_HAS_CFB24
+    case 24:
+	printk("24 bit color depth\n");
+	return &fbcon_cfb24;
+#endif
+#ifdef FBCON_HAS_CFB32
+    case 32:
+	printk("32 bit color depth\n");
+	return &fbcon_cfb32;
+#endif
+
+    default:
+	printk("unsupported color depth\n");
+	return NULL;
+    }
+}
+
+static void fbcon_clgen8_bmove(struct display *p, int sy, int sx, 
+				int dy, int dx, int height, int width)
+{
+    sx     *= p->fontwidth;
+    sy     *= p->fontheight;
+    dx     *= p->fontwidth;
+    dy     *= p->fontheight;
+    width  *= p->fontwidth;
+    height *= p->fontheight;
+
+    fb_info = (struct clgenfb_info*)p->fb_info;
+
+    clgen_BitBLT((unsigned short)sx, (unsigned short)sy,
+		 (unsigned short)dx, (unsigned short)dy,
+		 (unsigned short)width, (unsigned short)height,
+		 fb_info->currentmode.line_length);
+    clgen_WaitBLT();
+}
+
+static void fbcon_clgen8_clear(struct vc_data *conp, struct display *p, 
+				int sy, int sx, int height, int width)
+{
+    unsigned short col;
+    
+    fb_info = (struct clgenfb_info*)p->fb_info;
+
+    sx     *= p->fontwidth;
+    sy     *= p->fontheight;
+    width  *= p->fontwidth;
+    height *= p->fontheight;
+
+    col = attr_bgcol_ec(p, conp);
+    col &= 0xff;
+
+    clgen_RectFill((unsigned short)sx, (unsigned short)sy,
+		    (unsigned short)width,(unsigned short)height,
+		     col, fb_info->currentmode.line_length);
+    clgen_WaitBLT();
+}
+
+
+/********************************************************************/
+/* clgenfb_init() - master initialization function                  */
+/********************************************************************/
+__initfunc(void clgenfb_init(void))
+{
+    const struct ConfigDev *cd  = NULL;
+    const struct ConfigDev *cd2 = NULL;
+    int err;
+    int btype;
+    int key,key2;
+    unsigned long board_addr,board_size;
+
+    printk(">clgenfb_init()\n");
+    printk(KERN_INFO "clgen: Driver for Cirrus Logic based graphic boards, v" CLGEN_VERSION "\n");
+
+    btype = -1;
+
+    if ((key = zorro_find(ZORRO_PROD_HELFRICH_SD64_RAM, 0, 0)))
+    {
+	key2 = zorro_find(ZORRO_PROD_HELFRICH_SD64_REG, 0, 0);
+        btype = BT_SD64;
+        printk(KERN_INFO "clgen: SD64 board detected; ");
+    }
+    else if ((key = zorro_find(ZORRO_PROD_HELFRICH_PICCOLO_RAM, 0, 0)))
+    {
+        key2      = zorro_find(ZORRO_PROD_HELFRICH_PICCOLO_REG, 0, 0);
+    	btype = BT_PICCOLO;
+    	printk(KERN_INFO "clgen: Piccolo board detected; ");
+    }
+    else if ((key = zorro_find(ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, 0, 0)))
+    {
+        key2      = zorro_find(ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG, 0, 0);
+	btype = BT_PICASSO;
+    	printk(KERN_INFO "clgen: Picasso II board detected; ");
+    }
+    else if ((key = zorro_find(ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, 0, 0)))
+    {
+        key2      = zorro_find(ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG, 0, 0);
+        btype = BT_SPECTRUM;
+        printk(KERN_INFO "clgen: Spectrum board detected; ");
+    }
+    else if ((key = zorro_find(ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3, 0, 0)))
+    {
+        btype = BT_PICASSO4;
+        printk(KERN_INFO "clgen: Picasso 4 board detected; ");
+    }
+    else
+    {
+	printk(KERN_NOTICE "clgen: no supported board found.\n");
+	return;
+    }
+    
+    fb_info = &boards[0]; /* FIXME support multiple boards ...*/
+    
+    fb_info->keyRAM = key;
+    fb_info->keyREG = key2;
+    fb_info->btype  = btype;
+    
+    cd = zorro_get_board(key);
+    board_addr = (unsigned long)cd->cd_BoardAddr;
+    board_size = (unsigned long)cd->cd_BoardSize;
+    printk(" RAM (%lu MB) at $%lx, ", board_size/0x100000, board_addr);
+
+    if (btype == BT_PICASSO4)
+    {
+	printk(" REG at $%lx\n", board_addr + 0x600000);
+
+        /* To be precise, for the P4 this is not the */
+        /* begin of the board, but the begin of RAM. */
+	/* for P4, map in its address space in 2 chunks (### TEST! ) */
+	/* (note the ugly hardcoded 16M number) */
+	fb_info->regs = (unsigned char *)kernel_map(board_addr, 16777216, 
+	                                      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->fbmem = kernel_map(board_addr + 16777216, 16777216, 
+			      KERNELMAP_NOCACHE_SER, NULL);
+	DEBUG printk(KERN_INFO "clgen: (RAM start set to: $%lx)\n", fb_info->fbmem);
+    }
+    else
+    {
+        cd2 = zorro_get_board(key2);
+        printk(" REG at $%lx\n", (unsigned long)cd2->cd_BoardAddr);
+
+        if (board_addr > 0x01000000)
+	    fb_info->fbmem = kernel_map(board_addr, board_size, 
+				  KERNELMAP_NOCACHE_SER, NULL);
+	else
+	    fb_info->fbmem = ZTWO_VADDR(board_addr);
+
+        /* set address for REG area of board */
+	fb_info->regs = (unsigned char *)ZTWO_VADDR(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);
+    }
+
+    init_vgachip();
+
+    /* set up a few more things, register framebuffer driver etc */
+    fb_info->gen.parsize         = sizeof(struct clgenfb_par);
+    fb_info->gen.fbhw            = &clgen_hwswitch;
+    strcpy (fb_info->gen.info.modename, clgenfb_name);
+    fb_info->gen.info.node       = -1;
+    fb_info->gen.info.fbops      = &clgenfb_ops;
+    fb_info->gen.info.disp       = &disp;
+    fb_info->gen.info.changevar  = NULL;
+    fb_info->gen.info.switch_con = &fbgen_switch;
+    fb_info->gen.info.updatevar  = &fbgen_update_var;
+    fb_info->gen.info.blank      = &fbgen_blank;
+    
+    /* mark this board as "autoconfigured" */
+    zorro_config_board(key, 0);
+    if (btype != BT_PICASSO4)
+	zorro_config_board(key2, 0);
+
+    /* now that we know the board has been registered n' stuff, we */
+    /* can finally initialize it to a default mode (640x480) */
+    clgenfb_default = clgenfb_predefined[1].var;
+    clgenfb_default.activate = FB_ACTIVATE_NOW;
+    clgenfb_default.yres_virtual = 480*3; /* for fast scrolling (YPAN-Mode) */
+    err = fbgen_do_set_var(&clgenfb_default, 1, &fb_info->gen);
+
+    if (err)
+	return;
+
+    disp.var = clgenfb_default;
+    fbgen_set_disp(-1, &fb_info->gen);
+    fbgen_install_cmap(0, &fb_info->gen);
+
+    err = register_framebuffer(&fb_info->gen.info);
+    if (err)
+    {
+	printk(KERN_ERR "clgen: ERROR - could not register fb device; err = %d!\n", err);
+	return;
+    }
+
+    printk("<clgenfb_init()\n");
+    return;
+}
+
+    /*
+     *  Cleanup
+     */
+
+void clgenfb_cleanup(struct clgenfb_info *info)
+{
+    printk(">clgenfb_cleanup()\n");
+
+    fb_info = info;
+
+    switch_monitor(0);
+
+    zorro_unconfig_board(info->keyRAM, 0);
+    if (fb_info->btype != BT_PICASSO4)
+	zorro_unconfig_board(info->keyREG, 0);
+
+    unregister_framebuffer(&info->gen.info);
+    printk("Framebuffer unregistered\n");
+    printk("<clgenfb_cleanup()\n");
+}
+
+
+/* A strtok which returns empty strings, too */
+static char *strtoke(char *s,const char *ct)
+{
+	char *sbegin, *send;
+	static char *ssave = NULL;
+
+	sbegin  = s ? s : ssave;
+	if (!sbegin)
+		return NULL;
+	if (*sbegin == '\0') {
+		ssave = NULL;
+		return NULL;
+	}
+	send = strpbrk(sbegin, ct);
+	if (send && *send != '\0')
+		*send++ = '\0';
+	ssave = send;
+	return sbegin;
+}
+
+/*****************************************************************/
+/* clgenfb_setup() might be used later for parsing possible      */
+/* arguments to the video= bootstrap parameter. Right now, there */
+/* is nothing I do here.                                         */
+/*****************************************************************/
+__initfunc(void clgenfb_setup(char *options, int *ints))
+{
+//    char *this_opt;
+
+//    printk("clgenfb_setup(): options: %s\n", options);	
+}
+
+
+    /*
+     *  Modularization
+     */
+
+#ifdef MODULE
+int init_module(void)
+{
+    printk("init_module()\n");
+    clgenfb_init(0);
+    return 0;
+}
+
+void cleanup_module(void)
+{
+    printk("module_cleanup()\n");
+    clgenfb_cleanup(fb_info);
+}
+#endif /* MODULE */
+
+
+
+/**********************************************************************/
+/* about the following functions - I have used the same names for the */
+/* functions as Markus Wild did in his Retina driver for NetBSD as    */
+/* they just made sense for this purpose. Apart from that, I wrote    */
+/* these functions myself.                                            */
+/**********************************************************************/
+
+/*** WGen() - write into one of the external/general registers ***/
+void WGen(int regnum, unsigned char val)
+{
+	unsigned volatile char *reg = fb_info->regs + regnum;
+
+	if(fb_info->btype == BT_PICASSO)
+	{
+		/* Picasso II specific hack */
+/*		if (regnum == M_3C7_W || regnum == M_3C9 || regnum == VSSM2) */
+		if (regnum == M_3C7_W || regnum == M_3C9)
+			reg += 0xfff;
+	}
+
+	*reg = val;
+}
+
+/*** RGen() - read out one of the external/general registers ***/
+unsigned char RGen(int regnum)
+{
+	unsigned volatile char *reg = fb_info->regs + regnum;
+
+	if(fb_info->btype == BT_PICASSO)
+	{
+		/* Picasso II specific hack */
+/*		if (regnum == M_3C7_W || regnum == M_3C9 || regnum == VSSM2) */
+		if (regnum == M_3C7_W || regnum == M_3C9)
+			reg += 0xfff;
+	}
+
+	return *reg;
+}
+
+/*** WSeq() - write into a register of the sequencer ***/
+void WSeq(unsigned char regnum, unsigned char val)
+{
+	fb_info->regs[SEQRX]   = regnum;
+	fb_info->regs[SEQRX+1] = val;
+}
+
+/*** RSeq() - read out one of the Sequencer registers ***/
+unsigned char RSeq(unsigned char regnum)
+{
+	fb_info->regs[SEQRX] = regnum;
+	return fb_info->regs[SEQRX+1];
+}
+
+/*** WCrt() - write into a register of the CRT controller ***/
+void WCrt(unsigned char regnum, unsigned char val)
+{
+	fb_info->regs[CRTX]   = regnum;
+	fb_info->regs[CRTX+1] = val;
+}
+
+/*** RCrt() - read out one of the CRT controller registers ***/
+unsigned char RCrt(unsigned char regnum)
+{
+	fb_info->regs[CRTX] = regnum;
+	return fb_info->regs[CRTX+1];
+}
+
+/*** WGfx() - write into a register of the Gfx controller ***/
+void WGfx(unsigned char regnum, unsigned char val)
+{
+	fb_info->regs[GRX]   = regnum;
+	fb_info->regs[GRX+1] = val;
+}
+
+/*** RGfx() - read out one of the Gfx controller registers ***/
+unsigned char RGfx(unsigned char regnum)
+{
+	fb_info->regs[GRX] = regnum;
+	return fb_info->regs[GRX+1];
+}
+
+/*** WAttr() - write into a register of the Attribute controller ***/
+void WAttr(unsigned char regnum, unsigned char val)
+{
+	/* if the next access to the attribute controller is a data write access, */
+	/* simply write back the information that was already there before, so that */
+	/* the next write access after that will be an index write. */
+	if (RCrt(CRT24) & 0x80)
+		/* can't use WAttr() here - we would go into a recursive loop otherwise */
+		fb_info->regs[ARX] = fb_info->regs[ARX+1];
+
+	if (RCrt(CRT24) & 0x80)
+		printk(KERN_WARNING "clgen: *** AttrIdx BAD!***\n");
+
+	/* now, first set index and after that the value - both to the same address (!) */
+	fb_info->regs[ARX] = regnum;
+	fb_info->regs[ARX] = val;
+}
+
+/*** AttrOn() - turn on VideoEnable for Attribute controller ***/
+void AttrOn()
+{
+	if (RCrt(CRT24) & 0x80)
+		/* if we're just in "write value" mode, write back the */
+		/* same value as before to not modify anything */
+		fb_info->regs[ARX] = fb_info->regs[ARX+1];
+
+	/* turn on video bit */
+/*	fb_info->regs[ARX] = 0x20; */
+	fb_info->regs[ARX] = 0x33;
+
+	/* dummy write on Reg0 to be on "write index" mode next time */
+	fb_info->regs[ARX] = 0x00;
+}
+
+/*** RAttr() - read out a register of the Attribute controller ***/
+unsigned char RAttr(unsigned char regnum)
+{
+	/* (explanation see above in WAttr() ) */
+	if (RCrt(CRT24) & 0x80)
+		fb_info->regs[ARX] = fb_info->regs[ARX+1];
+
+	fb_info->regs[ARX] = regnum;
+	return fb_info->regs[ARX+1];
+}
+
+
+/*** WHDR() - write into the Hidden DAC register ***/
+/* as the HDR is the only extension register that requires special treatment 
+ * (the other extension registers are accessible just like the "ordinary"
+ * registers of their functional group) here is a specialized routine for 
+ * accessing the HDR
+ */
+void WHDR(unsigned char val)
+{
+	unsigned char dummy;
+
+	if(fb_info->btype == BT_PICASSO)
+	{
+		/* Klaus' hint for correct access to HDR on some boards */
+		/* first write 0 to pixel mask (3c6) */
+		WGen(M_3C6, 0x00); udelay(200);
+		/* next read dummy from pixel address (3c8) */
+		dummy = RGen(M_3C8); udelay(200);
+	}
+
+	/* now do the usual stuff to access the HDR */
+
+	dummy = RGen(M_3C6); udelay(200);
+	dummy = RGen(M_3C6); udelay(200);
+	dummy = RGen(M_3C6); udelay(200);
+	dummy = RGen(M_3C6); udelay(200);
+
+	WGen(M_3C6, val); udelay(200);
+
+	if(fb_info->btype == BT_PICASSO)
+	{
+		/* now first reset HDR access counter */
+		dummy = RGen(M_3C8); udelay(200);
+
+		/* and at the end, restore the mask value */
+		/* ## is this mask always 0xff? */
+		WGen(M_3C6, 0xff); udelay(200);
+	}
+}
+
+/*** RHDR() - read out the Hidden DAC register ***/
+/* I hope this does not break on the GD5428 - cannot test it. */
+/* (Is there any board for the Amiga that uses the 5428 ?) */
+unsigned char RHDR()
+{
+	unsigned char dummy;
+
+	dummy = RGen(M_3C6);
+	dummy = RGen(M_3C6);
+	dummy = RGen(M_3C6);
+	dummy = RGen(M_3C6);
+
+	return RGen(M_3C6);
+}
+
+
+/*** WSFR() - write to the "special function register" (SFR) ***/
+void WSFR(unsigned char val)
+{
+	fb_info->SFR          = val;
+	fb_info->regs[0x8000] = val;
+}
+
+/* The Picasso has a second register for switching the monitor bit */
+void WSFR2(unsigned char val)
+{
+	/* writing an arbitrary value to this one causes the monitor switcher */
+	/* to flip to Amiga display */
+	fb_info->SFR          = val;
+	fb_info->regs[0x9000] = val;
+}
+
+/*** WClut - set CLUT entry (range: 0..255 is automat. shifted to 0..63) ***/
+void WClut(unsigned char regnum, unsigned char red, unsigned char green, unsigned char blue)
+{
+	unsigned int data = 0x3c9;
+
+	/* address write mode register is not translated.. */
+	fb_info->regs[0x3c8] = regnum;
+
+	if(fb_info->btype == BT_PICASSO || fb_info->btype == BT_PICASSO4)
+	{
+		/* but DAC data register IS, at least for Picasso II */
+		if(fb_info->btype == BT_PICASSO)
+			data += 0xfff;
+		fb_info->regs[data] = (red   >> 2);
+		fb_info->regs[data] = (green >> 2);
+		fb_info->regs[data] = (blue  >> 2);
+	}
+	else
+	{
+		fb_info->regs[data] = (blue  >> 2);
+		fb_info->regs[data] = (green >> 2);
+		fb_info->regs[data] = (red   >> 2);
+	}
+}
+
+/*** RClut - read CLUT entry and convert to 0..255 range ***/
+void RClut(unsigned char regnum, unsigned char *red, unsigned char *green, unsigned char *blue)
+{
+	unsigned int data = 0x3c9;
+
+	fb_info->regs[0x3c7] = regnum;
+
+	if(fb_info->btype == BT_PICASSO || fb_info->btype == BT_PICASSO4)
+	{
+		if(fb_info->btype == BT_PICASSO)
+			data += 0xfff;
+		*red   = fb_info->regs[data] << 2;
+		*green = fb_info->regs[data] << 2;
+		*blue  = fb_info->regs[data] << 2;
+	}
+	else
+	{
+		*blue  = fb_info->regs[data] << 2;
+		*green = fb_info->regs[data] << 2;
+		*red   = fb_info->regs[data] << 2;
+	}
+}
+
+
+/*******************************************************************
+	clgen_WaitBLT()
+
+	Wait for the BitBLT engine to complete a possible earlier job
+*********************************************************************/
+
+void clgen_WaitBLT()
+{
+	/* now busy-wait until we're done */
+	while (RGfx(GR31) & 0x08)
+		;
+}
+
+/*******************************************************************
+	clgen_BitBLT()
+
+	perform accelerated "scrolling"
+********************************************************************/
+
+void clgen_BitBLT (u_short curx, u_short cury, u_short destx, u_short desty,
+		u_short width, u_short height, u_short line_length)
+{
+	u_short nwidth, nheight;
+	u_long nsrc, ndest;
+	u_char bltmode;
+
+	nwidth = width - 1;
+	nheight = height - 1;
+
+	bltmode = 0x00;
+	/* if source adr < dest addr, do the Blt backwards */
+	if (cury <= desty)
+	{
+		if (cury == desty)
+		{
+			/* if src and dest are on the same line, check x */
+			if (curx < destx)
+				bltmode |= 0x01;
+		}
+		else
+			bltmode |= 0x01;
+	}
+
+	if (!bltmode)
+	{
+		/* standard case: forward blitting */
+		nsrc = (cury * line_length) + curx;
+		ndest = (desty * line_length) + destx;
+	}
+	else
+	{
+		/* this means start addresses are at the end, counting backwards */
+		nsrc = cury * line_length + curx + nheight * line_length + nwidth;
+		ndest = desty * line_length + destx + nheight * line_length + nwidth;
+	}
+
+//	clgen_WaitBLT(); /* ### NOT OK for multiple boards! */
+
+	/*
+		run-down of registers to be programmed:
+		destination pitch
+		source pitch
+		BLT width/height
+		source start
+		destination start
+		BLT mode
+		BLT ROP
+		GR0 / GR1: "fill color"
+		start/stop
+	*/
+
+	/* pitch: set to line_length */
+	WGfx(GR24, line_length & 0xff);	/* dest pitch low */
+	WGfx(GR25, (line_length >> 8));	/* dest pitch hi */
+	WGfx(GR26, line_length & 0xff);	/* source pitch low */
+	WGfx(GR27, (line_length >> 8));	/* source pitch hi */
+
+	/* BLT width: actual number of pixels - 1 */
+	WGfx(GR20, nwidth & 0xff);	/* BLT width low */
+	WGfx(GR21, (nwidth >> 8));	/* BLT width hi */
+
+	/* BLT height: actual number of lines -1 */
+	WGfx(GR22, nheight & 0xff);	/* BLT height low */
+	WGfx(GR23, (nheight >> 8));	/* BLT width hi */
+
+	/* BLT destination */
+	WGfx(GR28, (u_char)(ndest & 0xff));	/* BLT dest low */
+	WGfx(GR29, (u_char)(ndest >> 8));	/* BLT dest mid */
+	WGfx(GR2A, (u_char)(ndest >> 16));	/* BLT dest hi */
+
+	/* BLT source */
+	WGfx(GR2C, (u_char)(nsrc & 0xff));	/* BLT src low */
+	WGfx(GR2D, (u_char)(nsrc >> 8));	/* BLT src mid */
+	WGfx(GR2E, (u_char)(nsrc >> 16));	/* BLT src hi */
+
+	/* BLT mode */
+	WGfx(GR30, bltmode);	/* BLT mode */
+
+	/* BLT ROP: SrcCopy */
+	WGfx(GR32, 0x0d);	/* BLT ROP */
+
+	/* and finally: GO! */
+	WGfx(GR31, 0x02);	/* BLT Start/status */
+}
+
+/*******************************************************************
+	clgen_RectFill()
+
+	perform accelerated rectangle fill
+********************************************************************/
+
+void clgen_RectFill (u_short x, u_short y, u_short width, u_short height,
+                     u_char color, u_short line_length)
+{
+	u_short nwidth, nheight;
+	u_long ndest;
+
+	nwidth = width - 1;
+	nheight = height - 1;
+
+	ndest = (y * line_length) + x;
+
+//	clgen_WaitBLT(); /* ### NOT OK for multiple boards! */
+
+	/* pitch: set to line_length */
+	WGfx(GR24, line_length & 0xff);	/* dest pitch low */
+	WGfx(GR25, (line_length >> 8));	/* dest pitch hi */
+	WGfx(GR26, line_length & 0xff);	/* source pitch low */
+	WGfx(GR27, (line_length >> 8));	/* source pitch hi */
+
+	/* BLT width: actual number of pixels - 1 */
+	WGfx(GR20, nwidth & 0xff);	/* BLT width low */
+	WGfx(GR21, (nwidth >> 8));	/* BLT width hi */
+
+	/* BLT height: actual number of lines -1 */
+	WGfx(GR22, nheight & 0xff);	/* BLT height low */
+	WGfx(GR23, (nheight >> 8));	/* BLT width hi */
+
+	/* BLT destination */
+	WGfx(GR28, (u_char)(ndest & 0xff));	/* BLT dest low */
+	WGfx(GR29, (u_char)(ndest >> 8));	/* BLT dest mid */
+	WGfx(GR2A, (u_char)(ndest >> 16));	/* BLT dest hi */
+
+	/* BLT source: set to 0 (is a dummy here anyway) */
+	WGfx(GR2C, 0x00);	/* BLT src low */
+	WGfx(GR2D, 0x00);	/* BLT src mid */
+	WGfx(GR2E, 0x00);	/* BLT src hi */
+
+	/* This is a ColorExpand Blt, using the */
+	/* same color for foreground and background */
+	WGfx(GR0, color);	/* foreground color */
+	WGfx(GR1, color);	/* background color */
+
+	/* BLT mode: color expand, Enable 8x8 copy (faster?) */
+	WGfx(GR30, 0xc0);	/* BLT mode */
+
+	/* BLT ROP: SrcCopy */
+	WGfx(GR32, 0x0d);	/* BLT ROP */
+
+	/* and finally: GO! */
+	WGfx(GR31, 0x02);	/* BLT Start/status */
+}
+
+/**************************************************************************
+ * bestclock() - determine closest possible clock lower(?) than the
+ * desired pixel clock
+ **************************************************************************/
+#define abs(x) ((x)<0 ? -(x) : (x))
+static void bestclock(long freq, long *best, long *nom,
+		      long *den, long *div,  long maxfreq)
+{
+    long n, h, d, f;
+
+    *nom = 0;
+    *den = 0;
+    *div = 0;
+
+    if (freq < 8000)
+	freq = 8000;
+
+    if (freq > maxfreq)
+	freq = maxfreq;
+
+    *best = 0;
+    f = freq * 10;
+
+    for(n = 32; n < 128; n++)
+    {
+        d = (143181 * n) / f;
+	if ( (d >= 7) && (d <= 63) )
+        {
+            if (d > 31)
+            	d = (d / 2) * 2;
+            h = (14318 * n) / d;
+            if ( abs(h - freq) < abs(*best - freq) )
+            {
+                *best = h;
+		*nom = n;
+		if (d < 32)
+		{
+                    *den = d;
+                    *div = 0;
+		}
+		else
+		{
+                    *den = d / 2;
+		    *div = 1;
+		}
+            }
+        }
+        d = ( (143181 * n)+f-1) / f;
+        if ( (d >= 7) && (d <= 63) )
+	{
+	    if (d > 31)
+    		d = (d / 2) * 2;
+	    h = (14318 * n) / d;
+	    if ( abs(h - freq) < abs(*best - freq) )
+	    {
+    	        *best = h;
+    	        *nom = n;
+            	if (d < 32)
+		{
+    	            *den = d;
+        	    *div = 0;
+	        }
+    	        else
+    	        {
+    	            *den = d / 2;
+	            *div = 1;
+	        }
+	    }
+	}
+    }
+}
+
diff -u --recursive --new-file v2.1.111/linux/drivers/video/clgenfb.h linux/drivers/video/clgenfb.h
--- v2.1.111/linux/drivers/video/clgenfb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/clgenfb.h	Sun Jul 26 14:40:19 1998
@@ -0,0 +1,175 @@
+
+/* definitions for Piccolo/SD64 VGA controller chip   */
+/* these definitions might most of the time also work */
+/* for other CL-GD542x/543x based boards..            */
+
+/*** External/General Registers ***/
+#define POS102	0x102  	/* POS102 register */
+#define VSSM	0x46e8 	/* Adapter Sleep */
+#define VSSM2	0x3c3	/* Motherboard Sleep */
+#define MISC_W	0x3c2	/* Miscellaneous Output register, write */
+#define MISC_R	0x3cc	/* Miscellaneous Output register, read */
+#define FC_W	0x3da	/* Feature Control Register, write (color) */
+#define FC_R	0x3ca	/* Feature Control Register, read */
+#define FEAT	0x3c2	/* Input Status Register 0 */
+#define STAT	0x3da	/* Input Status Register 1, read-only */
+#define M_3C6	0x3c6	/* Pixel Mask */
+#define M_3C7_W	0x3c7   /* Pixel Address Read Mode (write) */
+#define M_3C7_R	0x3c7	/* DAC State (read-only */
+#define M_3C8	0x3c8	/* Pixel Address Write Mode */
+#define M_3C9	0x3c9	/* Pixel Data */
+
+/*** VGA Sequencer Registers ***/
+#define SEQRX	0x3c4	/* Sequencer Index */
+#define SEQR0	0x0	/* Reset */
+#define SEQR1     0x1	/* Clocking Mode */
+#define SEQR2	0x2	/* Plane Mask / Write Pixel Extension */
+#define SEQR3	0x3	/* Character Map Select */
+#define SEQR4	0x4	/* Memory Mode */
+/* the following are from the "extension registers" group */
+#define SEQR6	0x6	/* Unlock ALL Extensions */
+#define SEQR7	0x7	/* Extended Sequencer Mode */
+#define SEQR8	0x8	/* EEPROM Control */
+#define SEQR9	0x9	/* Scratch Pad 0 (do not access!) */
+#define SEQRA	0xa	/* Scratch Pad 1 (do not access!) */
+#define SEQRB	0xb	/* VCLK0 Numerator */
+#define SEQRC	0xc	/* VCLK1 Numerator */
+#define SEQRD	0xd	/* VCLK2 Numerator */
+#define SEQRE	0xe	/* VCLK3 Numerator */
+#define SEQRF	0xf	/* DRAM Control */
+#define SEQR10	0x10	/* Graphics Cursor X Position */
+#define SEQR11	0x11	/* Graphics Cursor Y Position */
+#define SEQR12	0x12	/* Graphics Cursor Attributes */
+#define SEQR13	0x13	/* Graphics Cursor Pattern Address Offset */
+#define SEQR14	0x14	/* Scratch Pad 2 (CL-GD5426/'28 Only) (do not access!) */
+#define SEQR15	0x15	/* Scratch Pad 3 (CL-GD5426/'28 Only) (do not access!) */
+#define SEQR16	0x16	/* Performance Tuning (CL-GD5424/'26/'28 Only) */
+#define SEQR17	0x17	/* Configuration ReadBack and Extended Control (CL-GF5428 Only) */
+#define SEQR18	0x18	/* Signature Generator Control (Not CL-GD5420) */
+#define SEQR19	0x19	/* Signature Generator Result Low Byte (Not CL-GD5420) */
+#define SEQR1A	0x1a	/* Signature Generator Result High Byte (Not CL-GD5420) */
+#define SEQR1B	0x1b	/* VCLK0 Denominator and Post-Scalar Value */
+#define SEQR1C	0x1c	/* VCLK1 Denominator and Post-Scalar Value */
+#define SEQR1D	0x1d	/* VCLK2 Denominator and Post-Scalar Value */
+#define SEQR1E	0x1e	/* VCLK3 Denominator and Post-Scalar Value */
+#define SEQR1F	0x1f	/* BIOS ROM write enable and MCLK Select */
+
+/*** CRT Controller Registers ***/
+#define CRTX	0x3d4	/* CRTC Index */
+#define	CRT0	0x0	/* Horizontal Total */
+#define CRT1	0x1	/* Horizontal Display End */
+#define CRT2	0x2	/* Horizontal Blanking Start */
+#define CRT3	0x3	/* Horizontal Blabking End */
+#define CRT4	0x4	/* Horizontal Sync Start */
+#define CRT5	0x5	/* Horizontal Sync End */
+#define CRT6 	0x6	/* Vertical Total */
+#define CRT7	0x7	/* Overflow */
+#define CRT8	0x8	/* Screen A Preset Row Scan */
+#define CRT9	0x9	/* Character Cell Height */
+#define CRTA	0xa	/* Text Cursor Start */
+#define CRTB	0xb	/* Text Cursor End */
+#define CRTC	0xc	/* Screen Start Address High */
+#define CRTD	0xd	/* Screen Start Address Low */
+#define CRTE	0xe	/* Text Cursor Location High */
+#define CRTF	0xf	/* Text Cursor Location Low */
+#define CRT10	0x10	/* Vertical Sync Start */
+#define CRT11	0x11	/* Vertical Sync End */
+#define CRT12	0x12	/* Vertical Display End */
+#define CRT13	0x13	/* Offset */
+#define CRT14	0x14	/* Underline Row Scan */
+#define CRT15  	0x15	/* Vertical Blanking Start */
+#define CRT16	0x16	/* Vertical Blanking End */
+#define CRT17	0x17	/* Mode Control */
+#define CRT18	0x18	/* Line Compare */
+#define CRT22	0x22	/* Graphics Data Latches ReadBack */
+#define CRT24	0x24	/* Attribute Controller Toggle ReadBack */
+#define CRT26	0x26	/* Attribute Controller Index ReadBack */
+/* the following are from the "extension registers" group */
+#define CRT19	0x19	/* Interlace End */
+#define CRT1A	0x1a	/* Interlace Control */
+#define CRT1B	0x1b	/* Extended Display Controls */
+#define CRT1C	0x1c	/* Sync adjust and genlock register */
+#define CRT1D	0x1d	/* Overlay Extended Control register */
+#define CRT25	0x25	/* Part Status Register */
+#define CRT27	0x27	/* ID Register */
+#define CRT51	0x51	/* P4 disable "flicker fixer" */
+
+/*** Graphics Controller Registers ***/
+#define GRX	0x3ce	/* Graphics Controller Index */
+#define GR0	0x0	/* Set/Reset, Write Mode 5 Background Extension */
+#define GR1	0x1	/* Set/Reset Enable, Write Mode 4, 5 Foreground Ext. */
+#define GR2	0x2	/* Color Compare */
+#define GR3	0x3	/* Data Rotate */
+#define GR4	0x4	/* Read Map Select */
+#define GR5	0x5	/* Mode */
+#define GR6	0x6	/* Miscellaneous */
+#define GR7	0x7     /* Color Don't Care */
+#define GR8	0x8	/* Bit Mask */
+/* the following are from the "extension registers" group */
+#define GR9	0x9	/* Offset Register 0 */
+#define GRA	0xa	/* Offset Register 1 */
+#define GRB	0xb	/* Graphics Controller Mode Extensions */
+#define GRC	0xc	/* Color Key (CL-GD5424/'26/'28 Only) */
+#define GRD	0xd	/* Color Key Mask (CL-GD5424/'26/'28 Only) */
+#define GRE	0xe	/* Miscellaneous Control (Cl-GD5428 Only) */
+#define GRF	0xf	/* Display Compression Control register */
+#define GR10	0x10	/* 16-bit Pixel BG Color High Byte (Not CL-GD5420) */
+#define GR11	0x11	/* 16-bit Pixel FG Color High Byte (Not CL-GD5420) */
+#define GR12	0x12	/* Background Color Byte 2 Register */
+#define GR13	0x13	/* Foreground Color Byte 2 Register */
+#define GR14	0x14	/* Background Color Byte 3 Register */
+#define GR15	0x15	/* Foreground Color Byte 3 Register */
+/* the following are CL-GD5426/'28 specific blitter registers */
+#define GR20	0x20	/* BLT Width Low */
+#define GR21	0x21	/* BLT Width High */
+#define GR22	0x22	/* BLT Height Low */
+#define GR23	0x23	/* BLT Height High */
+#define GR24	0x24	/* BLT Destination Pitch Low */
+#define GR25	0x25	/* BLT Destination Pitch High */
+#define GR26	0x26	/* BLT Source Pitch Low */
+#define GR27	0x27	/* BLT Source Pitch High */
+#define GR28	0x28	/* BLT Destination Start Low */
+#define GR29	0x29	/* BLT Destination Start Mid */
+#define GR2A    0x2a	/* BLT Destination Start High */
+#define GR2C	0x2c	/* BLT Source Start Low */
+#define GR2D	0x2d	/* BLT Source Start Mid */
+#define GR2E	0x2e	/* BLT Source Start High */
+#define GR2F	0x2f	/* Picasso IV Blitter compat mode..? */
+#define GR30	0x30	/* BLT Mode */
+#define GR31	0x31	/* BLT Start/Status */
+#define GR32	0x32	/* BLT Raster Operation */
+#define GR33	0x33	/* another P4 "compat" register.. */
+#define GR34	0x34	/* Transparent Color Select Low */
+#define GR35	0x35	/* Transparent Color Select High */
+#define GR38	0x38	/* Source Transparent Color Mask Low */
+#define GR39	0x39	/* Source Transparent Color Mask High */
+
+/*** Attribute Controller Registers ***/
+#define ARX	0x3c0	/* Attribute Controller Index */
+#define AR0     0x0	/* Attribute Controller Palette Register 0 */
+#define AR1     0x1	/* Attribute Controller Palette Register 1 */
+#define AR2     0x2	/* Attribute Controller Palette Register 2 */
+#define AR3     0x3	/* Attribute Controller Palette Register 3 */
+#define AR4     0x4	/* Attribute Controller Palette Register 4 */
+#define AR5     0x5	/* Attribute Controller Palette Register 5 */
+#define AR6     0x6	/* Attribute Controller Palette Register 6 */
+#define AR7     0x7	/* Attribute Controller Palette Register 7 */
+#define AR8     0x8	/* Attribute Controller Palette Register 8 */
+#define AR9     0x9	/* Attribute Controller Palette Register 9 */
+#define ARA     0xa	/* Attribute Controller Palette Register 10 */
+#define ARB     0xb	/* Attribute Controller Palette Register 11 */
+#define ARC     0xc	/* Attribute Controller Palette Register 12 */
+#define ARD     0xd	/* Attribute Controller Palette Register 13 */
+#define ARE     0xe	/* Attribute Controller Palette Register 14 */
+#define ARF     0xf	/* Attribute Controller Palette Register 15 */
+#define AR10	0x10	/* Attribute Controller Mode Register */
+#define AR11	0x11	/* Overscan (Border) Color Register */
+#define AR12	0x12    /* Color Plane Enable Register */
+#define AR13	0x13	/* Pixel Panning Register */
+#define AR14	0x14	/* Color Select Register */
+#define AR33	0x33	/* The "real" Pixel Panning register (?) */
+#define AR34	0x34	/* *TEST* */
+
+/*** Extension Registers ***/
+#define HDR	0x3c6	/* Hidden DAC Register (Not CL-GD5420) */
+
diff -u --recursive --new-file v2.1.111/linux/drivers/video/controlfb.c linux/drivers/video/controlfb.c
--- v2.1.111/linux/drivers/video/controlfb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/controlfb.c	Sun Jul 26 14:40:19 1998
@@ -0,0 +1,997 @@
+/*
+ *  controlfb.c -- frame buffer device for the PowerMac 'control' display
+ *
+ *  Created 12 July 1998 by Dan Jacobowitz <dan@debian.org>
+ *  Copyright (C) 1998 Dan Jacobowitz
+ *
+ *  Frame buffer structure from:
+ *    drivers/video/chipsfb.c -- frame buffer device for
+ *    Chips & Technologies 65550 chip.
+ *
+ *    Copyright (C) 1998 Paul Mackerras
+ *
+ *    This file is derived from the Powermac "chips" driver:
+ *    Copyright (C) 1997 Fabio Riccardi.
+ *    And from the frame buffer device for Open Firmware-initialized devices:
+ *    Copyright (C) 1997 Geert Uytterhoeven.
+ *
+ *  Hardware information from:
+ *    control.c: Console support for PowerMac "control" display adaptor.
+ *    Copyright (C) 1996 Paul Mackerras
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/selection.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/nvram.h>
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#include <asm/vc_ioctl.h>
+#endif
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/adb.h>
+#include <asm/cuda.h>
+
+#include "fbcon.h"
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb16.h"
+#include "fbcon-cfb32.h"
+
+#include "macmodes.h"
+#include "controlfb.h"
+
+static int currcon = 0;
+static int switching = 0;
+
+struct fb_par_control {
+	int	vmode, cmode;
+	int	xres, yres;
+	int	vxres, vyres;
+	int	xoffset, yoffset;
+};
+
+struct fb_info_control {
+	struct fb_info			info;
+	struct fb_fix_screeninfo	fix;
+	struct fb_var_screeninfo	var;
+	struct display			disp;
+	struct fb_par_control		par;
+	struct {
+		__u8 red, green, blue;
+	}			palette[256];
+	
+	struct cmap_regs	*cmap_regs;
+	unsigned long		cmap_regs_phys;
+	
+	struct control_regs	*control_regs;
+	unsigned long		control_regs_phys;
+	
+	__u8			*frame_buffer;
+	unsigned long		frame_buffer_phys;
+	
+	int			sense, control_use_bank2;
+	unsigned long		total_vram;
+};
+
+/*
+ * Exported functions
+ */
+void control_init(void);
+void control_of_init(struct device_node *dp);
+
+static int control_open(struct fb_info *info, int user);
+static int control_release(struct fb_info *info, int user);
+static int control_get_fix(struct fb_fix_screeninfo *fix, int con,
+			 struct fb_info *info);
+static int control_get_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info);
+static int control_set_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info);
+static int control_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *info);
+static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info);
+static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info);
+static int control_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg, int con, struct fb_info *info);
+
+static int read_control_sense(struct fb_info_control *p);
+static inline int control_vram_reqd(int video_mode, int color_mode);
+static void set_control_clock(unsigned char *params);
+static void control_set_hardware(struct fb_info_control *p);
+static void control_par_to_all(struct fb_info_control *p, int init);
+static inline void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var);
+static int control_var_to_par(struct fb_var_screeninfo *var,
+	struct fb_par_control *par, const struct fb_info *fb_info);
+
+static void control_init_info(struct fb_info *info, struct fb_info_control *p);
+static void control_par_to_display(struct fb_par_control *par,
+  struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_control *p);
+static void control_init_display(struct display *disp);
+static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix,
+	struct fb_info_control *p);
+static void control_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_control *p);
+
+static struct fb_ops controlfb_ops = {
+	control_open,
+	control_release,
+	control_get_fix,
+	control_get_var,
+	control_set_var,
+	control_get_cmap,
+	control_set_cmap,
+	control_pan_display,
+	control_ioctl
+};
+
+static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green,
+			     u_int *blue, u_int *transp, struct fb_info *info);
+static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			     u_int transp, struct fb_info *info);
+static void do_install_cmap(int con, struct fb_info *info);
+
+
+__openfirmware
+
+
+static int control_open(struct fb_info *info, int user)
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int control_release(struct fb_info *info, int user)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int control_get_fix(struct fb_fix_screeninfo *fix, int con,
+			 struct fb_info *info)
+{
+	struct fb_info_control *cp = (struct fb_info_control *) info;
+
+	*fix = cp->fix;
+	return 0;
+}
+
+static int control_get_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info)
+{
+	struct fb_info_control *cp = (struct fb_info_control *) info;
+
+	*var = cp->var;
+	return 0;
+}
+
+/* Sets everything according to var */
+static int control_set_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info)
+{
+	struct fb_info_control *p = (struct fb_info_control *) info;
+	struct display *disp;
+	struct fb_par_control par;
+	int depthchange, err;
+
+	disp = (con >= 0) ? &fb_display[con] : &p->disp;
+	if((err = control_var_to_par(var, &par, info))) {
+		printk (KERN_ERR "Error in control_set_var, calling control_var_to_par: %d.\n", err);
+		return err;
+	}
+	
+	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) {
+		printk("Not activating, in control_set_var.\n");
+		control_par_to_var(&par, var);
+		return 0;
+	}
+/* I know, we want to use fb_display[con], but grab certain info from p->var instead. */
+#define DIRTY(x) (p->var.x != var->x)
+	depthchange = DIRTY(bits_per_pixel);
+	if(!DIRTY(xres) && !DIRTY(yres) && !DIRTY(xres_virtual) &&
+	   !DIRTY(yres_virtual) && !DIRTY(bits_per_pixel)) {
+	   	control_par_to_var(&par, var);
+		p->var = disp->var = *var;
+		return 0;
+	}
+printk("Original bpp is %d, new bpp %d.\n", p->var.bits_per_pixel, var->bits_per_pixel);
+	/* OK, we're getting here at the right times... */
+	p->par = par;
+	control_par_to_var(&par, var);
+	p->var = *var;
+	control_par_to_fix(&par, &p->fix, p);
+	control_par_to_display(&par, disp, &p->fix, p);
+	p->disp = *disp;
+	
+	if(info->changevar && !switching)	/* Don't want to do this if just switching consoles. */
+		(*info->changevar)(con);
+	if(con == currcon)
+		control_set_hardware(p);
+	if(depthchange)
+		if((err = fb_alloc_cmap(&disp->cmap, 0, 0)))
+			return err;
+	if(depthchange || switching)
+		do_install_cmap(con, info);
+	return 0;
+}
+
+static int control_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *info)
+{
+	if (var->xoffset != 0 || var->yoffset != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info)
+{
+	if (con == currcon)		/* current console? */
+		return fb_get_cmap(cmap, &fb_display[con].var, kspc,
+				   controlfb_getcolreg, info);
+	if (fb_display[con].cmap.len)	/* non default colormap? */
+		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc? 0: 2);
+	else {
+		int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+		fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+	}
+	return 0;
+}
+
+static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			 struct fb_info *info)
+{
+	struct display *disp = &fb_display[con];
+	int err;
+
+	if (disp->cmap.len == 0) {
+		int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+		err = fb_alloc_cmap(&disp->cmap, size, 0);
+		if (err)
+			return err;
+	}
+
+	if (con == currcon)
+		return fb_set_cmap(cmap, &disp->var, kspc, controlfb_setcolreg,
+				   info);
+	fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
+	return 0;
+}
+
+static int control_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg, int con, struct fb_info *info)
+{
+	return -EINVAL;
+}
+
+static int controlfb_switch(int con, struct fb_info *info)
+{
+	if (fb_display[currcon].cmap.len)
+		fb_get_cmap(&fb_display[currcon].cmap,
+			    &fb_display[currcon].var, 1, controlfb_getcolreg,
+			    info);
+	currcon = con;
+#if 0
+	control_var_to_par(&fb_display[currcon].var, &par, info);
+	control_set_par(&par, info); /*STOPPEDHERE - did i define that? */
+	do_install_cmap(con, info);
+#else
+	/* I see no reason not to do this.  Minus info->changevar(). */
+	/* DOH.  This makes control_set_var compare, you guessed it, */
+	/* fb_display[con].var (first param), and fb_display[con].var! */
+	/* Perhaps I just fixed that... */
+	switching = 1;
+	control_set_var(&fb_display[con].var, con, info);
+	switching = 0;
+#endif
+	return 0;
+}
+
+static int controlfb_updatevar(int con, struct fb_info *info)
+{
+	return 0;
+}
+
+static void controlfb_blank(int blank_mode, struct fb_info *info)
+{
+/*
+ *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
+ *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
+ *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
+ *  to e.g. a video mode which doesn't support it. Implements VESA suspend
+ *  and powerdown modes on hardware that supports disabling hsync/vsync:
+ *    blank_mode == 2: suspend vsync
+ *    blank_mode == 3: suspend hsync
+ *    blank_mode == 4: powerdown
+ */
+/* [danj] I think there's something fishy about those constants... */
+	struct fb_info_control *p = (struct fb_info_control *) info;
+	int	ctrl;
+
+	ctrl = ld_le32(&p->control_regs->ctrl.r) | 0x33;
+	if (blank_mode)
+		--blank_mode;
+	if (blank_mode & VESA_VSYNC_SUSPEND)
+		ctrl &= ~3;
+	if (blank_mode & VESA_HSYNC_SUSPEND)
+		ctrl &= ~0x30;
+	out_le32(&p->control_regs->ctrl.r, ctrl);
+
+/* TODO: Figure out how the heck to powerdown this thing! */
+
+    return;
+}
+
+static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green,
+			     u_int *blue, u_int *transp, struct fb_info *info)
+{
+	struct fb_info_control *p = (struct fb_info_control *) info;
+
+	if (regno > 255)
+		return 1;
+	*red = p->palette[regno].red;
+	*green = p->palette[regno].green;
+	*blue = p->palette[regno].blue;
+	return 0;
+}
+
+static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			     u_int transp, struct fb_info *info)
+{
+	struct fb_info_control *p = (struct fb_info_control *) info;
+
+	if (regno > 255 || regno < 0)
+		return 1;
+	p->palette[regno].red = red;
+	p->palette[regno].green = green;
+	p->palette[regno].blue = blue;
+
+	out_8(&p->cmap_regs->addr, regno);	/* tell clut what addr to fill	*/
+	out_8(&p->cmap_regs->lut, red);		/* send one color channel at	*/
+	out_8(&p->cmap_regs->lut, green);	/* a time...			*/
+	out_8(&p->cmap_regs->lut, blue);
+
+	if(regno < 16) {
+#if 0
+#ifdef FBCON_HAS_CFB16
+		fbcon_cfb16_cmap[regno] = (red << 10) | (green << 5) | blue;
+#endif
+#ifdef FBCON_HAS_CFB32
+		fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue;
+		/* I think. */
+#endif
+#else
+#ifdef FBCON_HAS_CFB16
+		fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno;
+#endif
+#ifdef FBCON_HAS_CFB32
+		fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) | (regno << 8) | regno;
+		/* I think. */
+#endif
+#endif
+	}
+	return 0;
+}
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+	if (con != currcon)
+		return;
+	if (fb_display[con].cmap.len)
+		fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1,
+			    controlfb_setcolreg, info);
+	else {
+		int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+		fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1,
+			    controlfb_setcolreg, info);
+	}
+}
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+extern struct vc_mode display_info;
+extern struct fb_info *console_fb_info;
+#if 0
+extern int (*console_setmode_ptr)(struct vc_mode *, int);
+extern int (*console_set_cmap_ptr)(struct fb_cmap *, int, int,
+				   struct fb_info *);
+int console_setmode(struct vc_mode *, int);
+#endif
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+
+static inline int control_vram_reqd(int video_mode, int color_mode)
+{
+	return control_reg_init[video_mode-1]->vres
+		* control_reg_init[video_mode-1]->pitch[color_mode];
+}
+
+static void set_control_clock(unsigned char *params)
+{
+	struct adb_request req;
+	int i;
+
+	for (i = 0; i < 3; ++i) {
+		cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+			     0x50, i + 1, params[i]);
+		while (!req.complete)
+			cuda_poll();
+	}
+}
+
+
+__initfunc(static void init_control(struct fb_info_control *p))
+{
+	struct fb_par_control *par = &p->par;
+
+	p->sense = read_control_sense(p);
+	printk("Monitor sense value = 0x%x, ", p->sense);
+	/* Try to pick a video mode out of NVRAM if we have one. */
+	par->vmode = nvram_read_byte(NV_VMODE);
+	if(par->vmode <= 0 || par->vmode > VMODE_MAX || !control_reg_init[par->vmode - 1])
+		par->vmode = VMODE_CHOOSE;
+	if(par->vmode == VMODE_CHOOSE)
+		par->vmode = mac_map_monitor_sense(p->sense);
+	if(!control_reg_init[par->vmode - 1])
+		par->vmode = VMODE_640_480_60;
+
+	par->cmode = nvram_read_byte(NV_CMODE);
+	if(par->cmode < CMODE_8 || par->cmode > CMODE_32)
+		par->cmode = CMODE_8;
+	/*
+	 * Reduce the pixel size if we don't have enough VRAM.
+	 */
+	while(par->cmode > CMODE_8 && control_vram_reqd(par->vmode, par->cmode) > p->total_vram)
+		par->cmode--;
+	
+	printk("using video mode %d and color mode %d.\n", par->vmode, par->cmode);
+	
+	par->vxres = par->xres = control_reg_init[par->vmode - 1]->hres;
+	par->vyres = par->yres = control_reg_init[par->vmode - 1]->vres;
+	par->xoffset = par->yoffset = 0;
+	
+	control_par_to_all(p, 1);
+	
+	if (register_framebuffer(&p->info) < 0) {
+		kfree(p);
+		return;
+	}
+	control_set_hardware(p);
+	
+	printk("fb%d: control display adapter\n", GET_FB_IDX(p->info.node));	
+}
+
+/* Now how about actually saying, Make it so! */
+/* Some things in here probably don't need to be done each time. */
+static void control_set_hardware(struct fb_info_control *p)
+{
+	struct control_regvals	*init;
+	struct preg		*rp;
+	int			flags, ctrl, i;
+	int			vmode, cmode;
+	
+	vmode = p->par.vmode;
+	cmode = p->par.cmode;
+	
+	init = control_reg_init[vmode - 1];
+	
+	if (control_vram_reqd(vmode, cmode) > 0x200000)
+		flags = 0x51;
+	else if (p->control_use_bank2)
+		flags = 0x39;
+	else
+		flags = 0x31;
+	if (vmode >= VMODE_1280_960_75 && cmode >= CMODE_16)
+		ctrl = 0x7f;
+	else
+		ctrl = 0x3b;
+
+	/* Initialize display timing registers */
+	out_le32(&p->control_regs->ctrl.r, 0x43b);
+	
+	set_control_clock(init->clock_params);
+	
+	p->cmap_regs->addr = 0x20; p->cmap_regs->d2 = init->radacal_ctrl[cmode];
+	p->cmap_regs->addr = 0x21; p->cmap_regs->d2 = p->control_use_bank2 ? 0: 1;
+	p->cmap_regs->addr = 0x10; p->cmap_regs->d2 = 0;
+	p->cmap_regs->addr = 0x11; p->cmap_regs->d2 = 0;
+
+	rp = &p->control_regs->vswin;
+	for (i = 0; i < 16; ++i, ++rp)
+		out_le32(&rp->r, init->regs[i]);
+	
+	out_le32(&p->control_regs->pitch.r, init->pitch[cmode]);
+	out_le32(&p->control_regs->mode.r, init->mode[cmode]);
+	out_le32(&p->control_regs->flags.r, flags);
+	out_le32(&p->control_regs->start_addr.r, 0);
+	out_le32(&p->control_regs->reg18.r, 0x1e5);
+	out_le32(&p->control_regs->reg19.r, 0);
+
+	for (i = 0; i < 16; ++i) {
+		controlfb_setcolreg(color_table[i], default_red[i], default_grn[i],
+			default_blu[i], 0, (struct fb_info *)p);
+	}
+/* Does the above need to be here each time? -- danj */
+
+	/* Turn on display */
+	out_le32(&p->control_regs->ctrl.r, ctrl);
+	
+#ifdef CONFIG_FB_COMPAT_XPMAC
+	/* And let the world know the truth. */
+	if (!console_fb_info || console_fb_info == &p->info) {
+		display_info.height = p->var.yres;
+		display_info.width = p->var.xres;
+		display_info.depth = (cmode == CMODE_32) ? 32 :
+			((cmode == CMODE_16) ? 16 : 8);
+		display_info.pitch = p->fix.line_length;
+		display_info.mode = vmode;
+		strncpy(display_info.name, "control",
+			sizeof(display_info.name));
+		display_info.fb_address = p->frame_buffer_phys
+			 + control_reg_init[vmode-1]->offset[cmode];
+		display_info.cmap_adr_address = p->cmap_regs_phys;
+		display_info.cmap_data_address = p->cmap_regs_phys + 0x30;
+		display_info.disp_reg_address = p->control_regs_phys;
+		console_fb_info = &p->info;
+	}
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+}
+
+__initfunc(void control_init(void))
+{
+#ifndef CONFIG_FB_OF
+	struct device_node *dp;
+
+	dp = find_devices("control");
+	if (dp != 0)
+		control_of_init(dp);
+#endif /* CONFIG_FB_OF */
+}
+
+__initfunc(void control_of_init(struct device_node *dp))
+{
+	struct fb_info_control	*p;
+	unsigned long		addr, size;
+	int			i, bank1, bank2;
+	
+	if(dp->next != 0)
+		printk("Warning: only using first control display device.\n");
+		/* danj: I have a feeling this no longer applies - if we somehow *
+		 * had two of them, they'd be two framebuffers, right?           */
+	if(dp->n_addrs != 2)
+		panic("expecting 2 address for control (got %d)", dp->n_addrs);
+	p = kmalloc(sizeof(*p), GFP_ATOMIC);
+	if (p == 0)
+		return;
+
+	/* Map in frame buffer and registers */
+	for (i = 0; i < dp->n_addrs; ++i) {
+		addr = dp->addrs[i].address;
+		size = dp->addrs[i].size;
+		if (size >= 0x800000) {
+			/* use the big-endian aperture (??) */
+			addr += 0x800000;
+			/* map at most 8MB for the frame buffer */
+			p->frame_buffer_phys = addr;
+			p->frame_buffer = __ioremap(addr, 0x800000, _PAGE_WRITETHRU);
+		} else {
+			p->control_regs_phys = addr;
+			p->control_regs = ioremap(addr, size);
+		}
+	}
+	p->cmap_regs_phys = 0xf301b000;	 /* XXX not in prom? */
+	p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000);
+
+	/* Work out which banks of VRAM we have installed. */
+	/* danj: I guess the card just ignores writes to nonexistant VRAM... */
+	p->frame_buffer[0] = 0x5a;
+	p->frame_buffer[1] = 0xc7;
+	bank1 = p->frame_buffer[0] == 0x5a && p->frame_buffer[1] == 0xc7;
+	p->frame_buffer[0x600000] = 0xa5;
+	p->frame_buffer[0x600001] = 0x38;
+	bank2 = p->frame_buffer[0x600000] == 0xa5 && p->frame_buffer[0x600001] == 0x38;
+	p->total_vram = (bank1 + bank2) * 0x200000;
+	/* If we don't have bank 1 installed, we hope we have bank 2 :-) */
+	p->control_use_bank2 = !bank1;
+	if (p->control_use_bank2)
+		p->frame_buffer += 0x600000;
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#if 0
+	console_set_cmap_ptr = control_set_cmap;
+	console_setmode_ptr = control_console_setmode;
+#endif
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+
+	init_control(p);
+}
+
+/*
+ * Get the monitor sense value.
+ * Note that this can be called before calibrate_delay,
+ * so we can't use udelay.
+ *
+ * Hmm - looking at platinum, should we be calling eieio() here?
+ */
+static int read_control_sense(struct fb_info_control *p)
+{
+	int sense;
+
+	out_le32(&p->control_regs->mon_sense.r, 7);	/* drive all lines high */
+	__delay(200);
+	out_le32(&p->control_regs->mon_sense.r, 077);	/* turn off drivers */
+	__delay(2000);
+	sense = (in_le32(&p->control_regs->mon_sense.r) & 0x1c0) << 2;
+
+	/* drive each sense line low in turn and collect the other 2 */
+	out_le32(&p->control_regs->mon_sense.r, 033);	/* drive A low */
+	__delay(2000);
+	sense |= (in_le32(&p->control_regs->mon_sense.r) & 0xc0) >> 2;
+	out_le32(&p->control_regs->mon_sense.r, 055);	/* drive B low */
+	__delay(2000);
+	sense |= ((in_le32(&p->control_regs->mon_sense.r) & 0x100) >> 5)
+		| ((in_le32(&p->control_regs->mon_sense.r) & 0x40) >> 4);
+	out_le32(&p->control_regs->mon_sense.r, 066);	/* drive C low */
+	__delay(2000);
+	sense |= (in_le32(&p->control_regs->mon_sense.r) & 0x180) >> 7;
+
+	out_le32(&p->control_regs->mon_sense.r, 077);	/* turn off drivers */
+	
+	return sense;
+}
+
+#if 1
+/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
+static int control_var_to_par(struct fb_var_screeninfo *var, 
+	struct fb_par_control *par, const struct fb_info *fb_info)
+{
+	int xres = var->xres;
+	int yres = var->yres;
+	int bpp = var->bits_per_pixel;
+	
+	struct control_regvals *init;
+	struct fb_info_control *p = (struct fb_info_control *) fb_info;
+
+    /*
+     *  Get the video params out of 'var'. If a value doesn't fit, round it up,
+     *  if it's too big, return -EINVAL.
+     *
+     *  Suggestion: Round up in the following order: bits_per_pixel, xres,
+     *  yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
+     *  bitfields, horizontal timing, vertical timing.
+     */
+	/* swiped by jonh from atyfb.c */
+	if (xres <= 512 && yres <= 384)
+		par->vmode = VMODE_512_384_60;		 /* 512x384, 60Hz */
+	else if (xres <= 640 && yres <= 480)
+		par->vmode = VMODE_640_480_67;		/* 640x480, 67Hz */
+	else if (xres <= 640 && yres <= 870)
+		par->vmode = VMODE_640_870_75P;		/* 640x870, 75Hz (portrait) */
+	else if (xres <= 768 && yres <= 576)
+		par->vmode = VMODE_768_576_50I;		/* 768x576, 50Hz (PAL full frame) */
+	else if (xres <= 800 && yres <= 600)
+		par->vmode = VMODE_800_600_75;		/* 800x600, 75Hz */
+	else if (xres <= 832 && yres <= 624)
+		par->vmode = VMODE_832_624_75;		/* 832x624, 75Hz */
+	else if (xres <= 1024 && yres <= 768)
+		par->vmode = VMODE_1024_768_75;		/* 1024x768, 75Hz */
+	else if (xres <= 1152 && yres <= 870)
+		par->vmode = VMODE_1152_870_75;		/* 1152x870, 75Hz */
+	else if (xres <= 1280 && yres <= 960)
+		par->vmode = VMODE_1280_960_75;		/* 1280x960, 75Hz */
+	else if (xres <= 1280 && yres <= 1024)
+		par->vmode = VMODE_1280_1024_75;	/* 1280x1024, 75Hz */
+	else
+		return -EINVAL;
+
+	xres = control_reg_init[par->vmode-1]->hres;
+	yres = control_reg_init[par->vmode-1]->vres;
+
+/*
+	if (var->xres_virtual <= xres)
+		par->vxres = xres;
+	else
+		par->vxres = (var->xres_virtual+7) & ~7;
+	if (var->yres_virtual <= yres)
+		par->vyres = yres;
+	else
+		par->vyres = var->yres_virtual;
+
+	par->xoffset = (var->xoffset+7) & ~7;
+	par->yoffset = var->yoffset;
+	if (par->xoffset+xres > par->vxres || par->yoffset+yres > par->vyres)
+		return -EINVAL;
+*/
+
+	/* I'm too chicken to think about virtual	*/
+	/* resolutions just yet. Bok bok.			*/
+	
+	/* And I'm too chicken to even figure out what they are.  Awk awk. [danj] */
+	if (var->xres_virtual > xres || var->yres_virtual > yres
+		|| var->xoffset != 0 || var->yoffset != 0) {
+		return -EINVAL;
+	}
+
+	par->xres = xres;
+	par->yres = yres;
+	par->vxres = xres;
+	par->vyres = yres;
+	par->xoffset = 0;
+	par->yoffset = 0;
+
+	if (bpp <= 8)
+		par->cmode = CMODE_8;
+	else if (bpp <= 16)
+		par->cmode = CMODE_16;
+	else if (bpp <= 32)
+		par->cmode = CMODE_32;
+	else
+		return -EINVAL;
+
+	if (control_vram_reqd(par->vmode, par->cmode) > p->total_vram)
+		return -EINVAL;
+
+	/* Check if we know about the wanted video mode */
+	init = control_reg_init[par->vmode-1];
+	if (init == NULL) {
+		/* I'm not sure if control has any specific requirements --	*/
+		/* if we have a regvals struct, we're good to go?		*/
+		return -EINVAL;
+	}
+
+	return 0;
+}
+#else
+/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
+static int control_var_to_par(struct fb_var_screeninfo *var, 
+	struct fb_par_control *par, const struct fb_info *fb_info)
+{
+	struct fb_info_control *p = (struct fb_info_control *) fb_info;
+	
+	if(mac_var_to_vmode(var, &par->vmode, &par->cmode) != 0)
+		return -EINVAL;
+	par->xres = par->vxres = vmode_attrs[par->vmode - 1].hres;
+	par->yres = par->vyres = vmode_attrs[par->vmode - 1].vres;
+	par->xoffset = par->yoffset = 0;
+	
+	if (control_vram_reqd(par->vmode, par->cmode) > p->total_vram)
+		return -EINVAL;
+
+	/* Check if we know about the wanted video mode */
+	if(!control_reg_init[par->vmode-1]) {
+		/* I'm not sure if control has any specific requirements --	*/
+		/* if we have a regvals struct, we're good to go?		*/
+		return -EINVAL;
+	}
+	return 0;
+}
+#endif
+
+#if 1
+static void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var)
+{
+	memset(var, 0, sizeof(*var));
+	var->xres = control_reg_init[par->vmode - 1]->hres;
+	var->yres = control_reg_init[par->vmode - 1]->vres;
+	var->xres_virtual = var->xres;
+	var->yres_virtual = var->yres;	/* For now. */
+	var->xoffset = par->xoffset;
+	var->yoffset = par->yoffset;
+	var->grayscale = 0;
+	
+	if(par->cmode != CMODE_8 && par->cmode != CMODE_16 && par->cmode != CMODE_32) {
+		printk(KERN_ERR "Bad color mode in control_par_to_var()!\n");
+		par->cmode = CMODE_8;
+	}
+	switch(par->cmode) {
+	case CMODE_8:
+		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;
+		break;
+	case CMODE_16:	/* RGB 555 */
+		var->bits_per_pixel = 16;
+		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 = 0;
+		var->transp.length = 0;
+		break;
+	case CMODE_32:	/* RGB 888 */
+		var->bits_per_pixel = 32;
+		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;
+		break;
+	}
+	var->red.msb_right = 0;
+	var->green.msb_right = 0;
+	var->blue.msb_right = 0;
+	var->transp.msb_right = 0;
+	var->nonstd = 0;
+	var->activate = 0;
+	var->height = -1;
+	var->width = -1;
+	var->vmode = FB_VMODE_NONINTERLACED;
+
+	/* these are total guesses, copied right out of atyfb.c */
+	var->left_margin = var->right_margin = 64;
+	var->upper_margin = var->lower_margin = 32;
+	var->hsync_len = /*64*/8;
+	var->vsync_len = /*2*/8;
+	var->sync = 0;
+
+#if 0
+/* jonh's pixclocks...*/
+	/* no long long support in the kernel :-( */
+	/* this splittig trick will work if xres > 232 */
+	var->pixclock = 1000000000/
+	(var->left_margin+var->xres+var->right_margin+var->hsync_len);
+	var->pixclock *= 1000;
+	var->pixclock /= vmode_attrs[par->vmode-1].vfreq*
+	 (var->upper_margin+var->yres+var->lower_margin+var->vsync_len);
+#else
+/* danj's */
+	/* 10^12 * clock_params[0] / (3906400 * clock_params[1] * 2^clock_params[2]) */
+	/* (10^12 * clock_params[0] / (3906400 * clock_params[1])) >> clock_params[2] */
+	/* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */
+	var->pixclock = 255990 * control_reg_init[par->vmode-1]->clock_params[0];
+	var->pixclock /= control_reg_init[par->vmode-1]->clock_params[1];
+	var->pixclock >>= control_reg_init[par->vmode-1]->clock_params[2];
+#endif
+}
+#else
+static inline void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var)
+{
+	mac_vmode_to_var(par->vmode, par->cmode, var);
+}
+#endif
+
+static void control_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_control *p)
+{
+	memset(fix, 0, sizeof(*fix));
+	strcpy(fix->id, "control");
+	fix->mmio_start = (char *)p->control_regs_phys;
+	fix->mmio_len = sizeof(struct control_regs);
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	
+	/*
+		fix->type_aux = 0;
+		fix->ywrapstep = 0;
+		fix->ypanstep = 0;
+		fix->xpanstep = 0;
+	*/
+}
+
+/* Fix must already be inited ^^^^^^^ */
+static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix,
+	struct fb_info_control *p)
+{
+	fix->smem_start = (void *)(p->frame_buffer_phys
+		+ control_reg_init[par->vmode-1]->offset[par->cmode]);
+	p->fix.smem_len = control_vram_reqd(par->vmode, par->cmode);
+		/* Hmm, jonh used total_vram here. */
+	p->fix.visual = (par->cmode == CMODE_8) ?
+		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+	p->fix.line_length = par->vxres << par->cmode;
+		/* ywrapstep, xpanstep, ypanstep */
+}
+
+static void control_init_display(struct display *disp)
+{
+	memset(disp, 0, sizeof(*disp));
+	disp->type = /* fix->type */ FB_TYPE_PACKED_PIXELS;
+	disp->can_soft_blank = 1;
+	disp->scrollmode = SCROLL_YREDRAW;
+#if 0
+		disp->type_aux = fix->type_aux;
+		disp->cmap.red = NULL;	/* ??? danj */
+		disp->cmap.green = NULL;
+		disp->cmap.blue = NULL;
+		disp->cmap.transp = NULL;
+			/* Yeah, I realize I just set 0 = 0. */
+#endif
+}
+
+static void control_par_to_display(struct fb_par_control *par,
+  struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_control *p)
+{
+	disp->var = p->var;
+	disp->screen_base = (char *) p->frame_buffer
+		 + control_reg_init[par->vmode-1]->offset[par->cmode];
+	disp->visual = fix->visual;
+	disp->line_length = fix->line_length;
+
+if(disp->scrollmode != SCROLL_YREDRAW) {
+	printk(KERN_ERR "Scroll mode not YREDRAW in control_par_to_display!!\n");
+	disp->scrollmode = SCROLL_YREDRAW;
+}
+	disp->dispsw = (par->cmode == CMODE_32) ? &fbcon_cfb32 :
+		((par->cmode == CMODE_16) ? &fbcon_cfb16 : &fbcon_cfb8);
+}
+
+static void control_init_info(struct fb_info *info, struct fb_info_control *p)
+{
+	strcpy(info->modename, p->fix.id);
+	info->node = -1;	/* ??? danj */
+	info->fbops = &controlfb_ops;
+	info->disp = &p->disp;
+	info->fontname[0] = 0;
+	info->changevar = NULL;
+	info->switch_con = &controlfb_switch;
+	info->updatevar = &controlfb_updatevar;
+	info->blank = &controlfb_blank;
+}
+
+/* danj: Oh, I HOPE I didn't miss anything major in here... */
+static void control_par_to_all(struct fb_info_control *p, int init)
+{
+	if(init) {
+		control_init_fix(&p->fix, p);
+	}
+	control_par_to_fix(&p->par, &p->fix, p);
+
+	control_par_to_var(&p->par, &p->var);
+
+	if(init) {
+		control_init_display(&p->disp);
+	}
+	control_par_to_display(&p->par, &p->disp, &p->fix, p);
+	
+	if(init) {
+		control_init_info(&p->info, p);
+	}
+}
+
+#if 0
+__initfunc(void controlfb_setup(char *options, int *ints))
+{
+    /* Parse user speficied options (`video=controlfb:') */
+	FUNCID;
+}
+
+static int controlfb_pan_display(struct fb_var_screeninfo *var,
+			   struct controlfb_par *par,
+			   const struct fb_info *fb_info)
+{
+    /*
+     *  Pan (or wrap, depending on the `vmode' field) the display using the
+     *  `xoffset' and `yoffset' fields of the `var' structure.
+     *  If the values don't fit, return -EINVAL.
+     */
+
+	FUNCID;
+
+    return 0;
+}
+
+#endif
diff -u --recursive --new-file v2.1.111/linux/drivers/video/controlfb.h linux/drivers/video/controlfb.h
--- v2.1.111/linux/drivers/video/controlfb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/controlfb.h	Sun Jul 26 14:40:19 1998
@@ -0,0 +1,262 @@
+/*
+ * controlfb_hw.h: Constants of all sorts for controlfb
+ *
+ * Copyright (C) 1998 Daniel Jacobowitz <dan@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Based on an awful lot of code, including:
+ *
+ * control.c: Console support for PowerMac "control" display adaptor.
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * The so far unpublished platinumfb.c
+ * Copyright (C) 1998 Jon Howell
+ */
+
+/*
+ * Structure of the registers for the RADACAL colormap device.
+ */
+struct cmap_regs {
+	unsigned char addr;
+	char pad1[15];
+	unsigned char d1;
+	char pad2[15];
+	unsigned char d2;
+	char pad3[15];
+	unsigned char lut;
+	char pad4[15];
+};
+
+/*
+ * Structure of the registers for the "control" display adaptor.
+ */
+#define PAD(x)	char x[12]
+
+struct preg {			/* padded register */
+	unsigned r;
+	char pad[12];
+};
+
+struct control_regs {
+	struct preg vcount;	/* vertical counter */
+	/* Vertical parameters are in units of 1/2 scan line */
+	struct preg vswin;	/* between vsblank and vssync */
+	struct preg vsblank;	/* vert start blank */
+	struct preg veblank;	/* vert end blank (display start) */
+	struct preg vewin;	/* between vesync and veblank */
+	struct preg vesync;	/* vert end sync */
+	struct preg vssync;	/* vert start sync */
+	struct preg vperiod;	/* vert period */
+	struct preg reg8;
+	/* Horizontal params are in units of 2 pixels */
+	struct preg hperiod;	/* horiz period - 2 */
+	struct preg hsblank;	/* horiz start blank */
+	struct preg heblank;	/* horiz end blank */
+	struct preg hesync;	/* horiz end sync */
+	struct preg hssync;	/* horiz start sync */
+	struct preg rege;
+	struct preg regf;
+	struct preg reg10;
+	struct preg reg11;
+	struct preg ctrl;	/* display control */
+	struct preg start_addr;	/* start address: 5 lsbs zero */
+	struct preg pitch;	/* addrs diff between scan lines */
+	struct preg mon_sense;	/* monitor sense bits */
+	struct preg flags;
+	struct preg mode;
+	struct preg reg18;
+	struct preg reg19;
+	struct preg res[6];
+};
+
+/*
+ * Register initialization tables for the control display.
+ *
+ * Dot clock rate is
+ * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0].
+ *
+ * The values for vertical frequency (V) in the comments below
+ * are the values measured using the modes under MacOS.
+ */
+struct control_regvals {
+	int	pitch[3];		/* bytes/line, indexed by color_mode */
+	int	offset[3];		/* first pixel address */
+	unsigned regs[16];		/* for vswin .. reg10 */
+	unsigned char mode[3];		/* indexed by color_mode */
+	unsigned char radacal_ctrl[3];
+	unsigned char clock_params[3];
+	int	hres;
+	int	vres;
+};
+
+/* Register values for 1280x1024, 75Hz mode (20) */
+static struct control_regvals control_reg_init_20 = {
+	{ 1280, 2560, 0 },
+	{ 0x10, 0x20, 0 },
+	{ 2129, 2128, 80, 42, 4, 2130, 2132, 88,
+	  420, 411, 91, 35, 421, 18, 211, 386, },
+	{ 1, 1, 1},
+	{ 0x50, 0x64, 0x64 },
+	{ 13, 56, 3 },	/* pixel clock = 134.61MHz for V=74.81Hz */
+	1280, 1024
+};
+
+/* Register values for 1280x960, 75Hz mode (19) */
+static struct control_regvals control_reg_init_19 = {
+	{ 1280, 2560, 0 },
+	{ 0x10, 0x20, 0 },
+	{ 1997, 1996, 76, 40, 4, 1998, 2000, 86,
+	  418, 409, 89, 35, 419, 18, 210, 384, },
+	{ 1, 1, 1 },
+	{ 0x50, 0x64, 0x64 },
+	{ 31, 125, 3 },	/* pixel clock = 126.01MHz for V=75.01 Hz */
+	1280, 960
+};
+
+/* Register values for 1152x870, 75Hz mode (18) */
+static struct control_regvals control_reg_init_18 = {
+	{ 1152, 2304, 4608 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1825, 1822, 82, 43, 4, 1828, 1830, 120,
+	  726, 705, 129, 63, 727, 32, 364, 664 },
+	{ 2, 1, 1 },
+	{ 0x10, 0x14, 0x28 },
+	{ 19, 61, 3 },	/* pixel clock = 100.33MHz for V=75.31Hz */
+	1152, 870
+};
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct control_regvals control_reg_init_17 = {
+	{ 1024, 2048, 4096 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1603, 1600, 64, 34, 4, 1606, 1608, 120,
+	  662, 641, 129, 47, 663, 24, 332, 616 },
+	{ 2, 1, 1 },
+	{ 0x10, 0x14, 0x28 },
+	{ 11, 28, 3 },	/* pixel clock = 79.55MHz for V=74.50Hz */
+	1024, 768
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct control_regvals control_reg_init_15 = {
+	{ 1024, 2048, 4096 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1607, 1604, 68, 39, 10, 1610, 1612, 132,
+	  670, 653, 141, 67, 671, 34, 336, 604, },
+	{ 2, 1, 1 },
+	{ 0x10, 0x14, 0x28 },
+	{ 12, 30, 3 },	/* pixel clock = 78.12MHz for V=72.12Hz */
+	1024, 768
+};
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct control_regvals control_reg_init_14 = {
+	{ 1024, 2048, 4096 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1607, 1604, 68, 39, 10, 1610, 1612, 132,
+	  670, 653, 141, 67, 671, 34, 336, 604, },
+	{ 2, 1, 1 },
+	{ 0x10, 0x14, 0x28 },
+	{ 15, 31, 3 },	/* pixel clock = 64.58MHz for V=59.62Hz */
+	1024, 768
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct control_regvals control_reg_init_13 = {
+	{ 832, 1664, 3328 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1331, 1330, 82, 43, 4, 1332, 1334, 128,
+	  574, 553, 137, 31, 575, 16, 288, 544 },
+	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+	{ 23, 42, 3 },	/* pixel clock = 57.07MHz for V=74.27Hz */
+	832, 624
+};
+
+/* Register values for 800x600, 75Hz mode (12) */
+static struct control_regvals control_reg_init_12 = {
+	{ 800, 1600, 3200 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1247, 1246, 46, 25, 4, 1248, 1250, 104,
+	  526, 513, 113, 39, 527, 20, 264, 488, },
+	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+	{ 7, 11, 3 },	/* pixel clock = 49.11MHz for V=74.40Hz */
+	800, 600
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct control_regvals control_reg_init_11 = {
+	{ 800, 1600, 3200 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1293, 1256, 56, 33, 10, 1330, 1332, 76,
+	  518, 485, 85, 59, 519, 30, 260, 460, },
+	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+	{ 17, 27, 3 },	/* pixel clock = 49.63MHz for V=71.66Hz */
+	800, 600
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct control_regvals control_reg_init_10 = {
+	{ 800, 1600, 3200 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1293, 1256, 56, 33, 10, 1330, 1332, 76,
+	  518, 485, 85, 59, 519, 30, 260, 460, },
+	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+	{ 20, 53, 2 },	/* pixel clock = 41.41MHz for V=59.78Hz */
+	800, 600
+};
+
+/* Register values for 640x870, 75Hz Full Page Display (7) */
+static struct control_regvals control_reg_init_7 = {
+        { 640, 1280, 2560 },
+	{ 0x10, 0x30, 0x68 },
+	{ 0x727, 0x724, 0x58, 0x2e, 0x4, 0x72a, 0x72c, 0x40,
+	  0x19e, 0x18c, 0x4c, 0x27, 0x19f, 0x14, 0xd0, 0x178 },
+	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+	{ 9, 33, 2 },	/* pixel clock = 57.29MHz for V=75.01Hz */
+	640, 870
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct control_regvals control_reg_init_6 = {
+	{ 640, 1280, 2560 },
+	{ 0, 8, 0x10 },
+	{ 1045, 1042, 82, 43, 4, 1048, 1050, 72,
+	  430, 393, 73, 31, 431, 16, 216, 400 },
+	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+	{ 14, 27, 2 },	/* pixel clock = 30.13MHz for V=66.43Hz */
+	640, 480
+};
+
+/* Register values for 640x480, 60Hz mode (5) */
+static struct control_regvals control_reg_init_5 = {
+	{ 640, 1280, 2560 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1037, 1026, 66, 34, 2, 1048, 1050, 56,
+	  398, 385, 65, 47, 399, 24, 200, 352, },
+	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+	{ 23, 37, 2 },	/* pixel clock = 25.14MHz for V=59.85Hz */
+	640, 480
+};
+
+static struct control_regvals *control_reg_init[VMODE_MAX] = {
+	NULL, NULL, NULL, NULL,
+	&control_reg_init_5,
+	&control_reg_init_6,
+	&control_reg_init_7,
+	NULL, NULL,
+	&control_reg_init_10,
+	&control_reg_init_11,
+	&control_reg_init_12,
+	&control_reg_init_13,
+	&control_reg_init_14,
+	&control_reg_init_15,
+	NULL,
+	&control_reg_init_17,
+	&control_reg_init_18,
+	&control_reg_init_19,
+	&control_reg_init_20
+};
diff -u --recursive --new-file v2.1.111/linux/drivers/video/creatorfb.c linux/drivers/video/creatorfb.c
--- v2.1.111/linux/drivers/video/creatorfb.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/creatorfb.c	Sun Jul 26 14:40:19 1998
@@ -1,4 +1,4 @@
-/* $Id: creatorfb.c,v 1.7 1998/07/21 10:36:48 jj Exp $
+/* $Id: creatorfb.c,v 1.10 1998/07/25 22:54:37 davem Exp $
  * creatorfb.c: Creator/Creator3D frame buffer driver
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
@@ -185,7 +185,7 @@
 	int x, y, w, h;
 	
 	fbc->ppc = 0x1803;
-	fbc->fg = ffb_cmap[attr_bg_col_ec(conp)];
+	fbc->fg = ffb_cmap[attr_bgcol_ec(p,conp)];
 	fbc->fbc = 0x2000707f;
 	fbc->rop = 0x83;
 	fbc->pmask = 0xffffffff;
@@ -207,13 +207,13 @@
 	fbc->bw = w;
 }
 
-static void ffb_fill(struct fb_info_sbusfb *fb, int s,
+static void ffb_fill(struct fb_info_sbusfb *fb, struct display *p, int s,
 		     int count, unsigned short *boxes)
 {
 	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
 
 	fbc->ppc = 0x1803;
-	fbc->fg = ffb_cmap[attr_bg_col(s)];
+	fbc->fg = ffb_cmap[attr_bgcol(p,s)];
 	fbc->fbc = 0x2000707f;
 	fbc->rop = 0x83;
 	fbc->pmask = 0xffffffff;
@@ -236,11 +236,15 @@
 
 	if (p->fontheightlog) {
 		xy = (yy << (16 + p->fontheightlog));
-		i = ((c & 0xff) << p->fontheightlog);
+		i = ((c & p->charmask) << p->fontheightlog);
 	} else {
 		xy = ((yy * p->fontheight) << 16);
-		i = (c & 0xff) * p->fontheight;
+		i = (c & p->charmask) * p->fontheight;
 	}
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+	fd = p->fontdata + i;
+	xy += (xx * 8) + fb->s.ffb.xy_margin;
+#else
 	if (p->fontwidth <= 8)
 		fd = p->fontdata + i;
 	else
@@ -249,24 +253,29 @@
 		xy += (xx << p->fontwidthlog) + fb->s.ffb.xy_margin;
 	else
 		xy += (xx * p->fontwidth) + fb->s.ffb.xy_margin;
+#endif
 	fbc->ppc = 0x203;
-	fbc->fg = ffb_cmap[attr_fg_col(c)];
+	fbc->fg = ffb_cmap[attr_fgcol(p,c)];
 	fbc->fbc = 0x2000707f;
 	fbc->rop = 0x83;
 	fbc->pmask = 0xffffffff;
-	fbc->bg = ffb_cmap[attr_bg_col(c)];
+	fbc->bg = ffb_cmap[attr_bgcol(p,c)];
 	fbc->fontw = p->fontwidth;
 	fbc->fontinc = 0x10000;
 	fbc->fontxy = xy;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
 	if (p->fontwidth <= 8) {
+#endif
 		for (i = 0; i < p->fontheight; i++)
 			fbc->font = *fd++ << 24;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
 	} else {
 		for (i = 0; i < p->fontheight; i++) {
 			fbc->font = *(u16 *)fd << 16;
 			fd += 2;
 		}
 	}
+#endif
 }
 
 static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
@@ -278,42 +287,51 @@
 	u8 *fd1, *fd2, *fd3, *fd4;
 
 	fbc->ppc = 0x203;
-	fbc->fg = ffb_cmap[attr_fg_col(*s)];
+	fbc->fg = ffb_cmap[attr_fgcol(p,*s)];
 	fbc->fbc = 0x2000707f;
 	fbc->rop = 0x83;
 	fbc->pmask = 0xffffffff;
-	fbc->bg = ffb_cmap[attr_bg_col(*s)];
+	fbc->bg = ffb_cmap[attr_bgcol(p,*s)];
 	xy = fb->s.ffb.xy_margin;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+	xy += xx * 8;
+#else
 	if (p->fontwidthlog)
 		xy += (xx << p->fontwidthlog);
 	else
 		xy += xx * p->fontwidth;
+#endif
 	if (p->fontheightlog)
 		xy += (yy << (16 + p->fontheightlog));
 	else
 		xy += ((yy * p->fontheight) << 16);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
 	if (p->fontwidth <= 8) {
+#endif
 		while (count >= 4) {
 			count -= 4;
 			fbc->fontw = 4 * p->fontwidth;
 			fbc->fontinc = 0x10000;
 			fbc->fontxy = xy;
 			if (p->fontheightlog) {
-				fd1 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
-				fd2 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
-				fd3 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
-				fd4 = p->fontdata + ((*s++ & 0xff) << p->fontheightlog);
+				fd1 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+				fd2 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+				fd3 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
+				fd4 = p->fontdata + ((*s++ & p->charmask) << p->fontheightlog);
 			} else {
-				fd1 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
-				fd2 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
-				fd3 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
-				fd4 = p->fontdata + ((*s++ & 0xff) * p->fontheight);
+				fd1 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+				fd2 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+				fd3 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
+				fd4 = p->fontdata + ((*s++ & p->charmask) * p->fontheight);
 			}
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
 			if (p->fontwidth == 8) {
+#endif
 				for (i = 0; i < p->fontheight; i++)
 					fbc->font = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) 
 						<< 8)) << 8)) << 8);
 				xy += 32;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
 			} else {
 				for (i = 0; i < p->fontheight; i++)
 					fbc->font = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) 
@@ -328,11 +346,11 @@
 			fbc->fontinc = 0x10000;
 			fbc->fontxy = xy;
 			if (p->fontheightlog) {
-				fd1 = p->fontdata + ((*s++ & 0xff) << (p->fontheightlog + 1));
-				fd2 = p->fontdata + ((*s++ & 0xff) << (p->fontheightlog + 1));
+				fd1 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1));
+				fd2 = p->fontdata + ((*s++ & p->charmask) << (p->fontheightlog + 1));
 			} else {
-				fd1 = p->fontdata + (((*s++ & 0xff) * p->fontheight) << 1);
-				fd2 = p->fontdata + (((*s++ & 0xff) * p->fontheight) << 1);
+				fd1 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1);
+				fd2 = p->fontdata + (((*s++ & p->charmask) * p->fontheight) << 1);
 			}
 			for (i = 0; i < p->fontheight; i++) {
 				fbc->font = ((((u32)*(u16 *)fd1) << p->fontwidth) | ((u32)*(u16 *)fd2)) << (16 - p->fontwidth);
@@ -340,6 +358,7 @@
 			}
 			xy += 2 * p->fontwidth;
 		}
+#endif
 	}
 	while (count) {
 		count--;
@@ -347,13 +366,16 @@
 		fbc->fontinc = 0x10000;
 		fbc->fontxy = xy;
 		if (p->fontheightlog)
-			i = ((*s++ & 0xff) << p->fontheightlog);
+			i = ((*s++ & p->charmask) << p->fontheightlog);
 		else
-			i = ((*s++ & 0xff) * p->fontheight);
+			i = ((*s++ & p->charmask) * p->fontheight);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
 		if (p->fontwidth <= 8) {
+#endif
 			fd1 = p->fontdata + i;
 			for (i = 0; i < p->fontheight; i++)
 				fbc->font = *fd1++ << 24;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
 		} else {
 			fd1 = p->fontdata + (i << 1);
 			for (i = 0; i < p->fontheight; i++) {
@@ -361,6 +383,7 @@
 				fd1 += 2;
 			}
 		}
+#endif
 		xy += p->fontwidth;
 	}
 }
@@ -471,11 +494,8 @@
 	strcpy(fb->info.modename, "Creator");
 		
 	strcpy(fix->id, "Creator");
-	fix->smem_start = (char *)(regs[0].phys_addr) + FFB_DFB24_POFF;
 	fix->visual = FB_VISUAL_DIRECTCOLOR;
 	fix->line_length = 8192;
-	fix->mmio_start = (char *)(regs[0].phys_addr) + FFB_FBC_REGS_POFF;
-	fix->mmio_len = PAGE_SIZE;
 	fix->accel = FB_ACCEL_SUN_CREATOR;
 	
 	var->bits_per_pixel = 32;
diff -u --recursive --new-file v2.1.111/linux/drivers/video/cyberfb.c linux/drivers/video/cyberfb.c
--- v2.1.111/linux/drivers/video/cyberfb.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/cyberfb.c	Sun Jul 26 14:40:19 1998
@@ -21,6 +21,7 @@
  */
 
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.111/linux/drivers/video/dnfb.c linux/drivers/video/dnfb.c
--- v2.1.111/linux/drivers/video/dnfb.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/dnfb.c	Sun Jul 26 14:40:19 1998
@@ -5,6 +5,7 @@
 #include <linux/tty.h>
 #include <linux/malloc.h>
 #include <linux/delay.h>
+#include <linux/config.h>
 #include <linux/interrupt.h>
 #include <asm/setup.h>
 #include <asm/segment.h>
diff -u --recursive --new-file v2.1.111/linux/drivers/video/dummycon.c linux/drivers/video/dummycon.c
--- v2.1.111/linux/drivers/video/dummycon.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/dummycon.c	Sun Jul 26 14:40:19 1998
@@ -5,7 +5,6 @@
  *  available, usually until fbcon takes console over.
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kdev_t.h>
 #include <linux/tty.h>
@@ -18,11 +17,7 @@
  *  Dummy console driver
  */
 
-#ifdef __sparc__
-/* Some reasonable defaults, so that we don't loose any text */
-#define DUMMY_COLUMNS	128
-#define DUMMY_ROWS	54
-#elif defined(CONFIG_ARM)
+#if defined(CONFIG_ARM)
 #define DUMMY_COLUMNS	ORIG_VIDEO_COLS
 #define DUMMY_ROWS	ORIG_VIDEO_LINES
 #else
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-afb.c linux/drivers/video/fbcon-afb.c
--- v2.1.111/linux/drivers/video/fbcon-afb.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-afb.c	Sun Jul 26 14:40:19 1998
@@ -251,7 +251,7 @@
     int fg, bg;
 
     dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx;
-    cdat0 = p->fontdata+(c&0xff)*p->fontheight;
+    cdat0 = p->fontdata+(c&p->charmask)*p->fontheight;
     fg = attr_fgcol(p,c);
     bg = attr_bgcol(p,c);
 
@@ -286,7 +286,7 @@
     u8 *dest, *dest0, *dest1, *expand;
     u8 *cdat1, *cdat2, *cdat3, *cdat4, *cdat10, *cdat20, *cdat30, *cdat40;
     u_short i, j;
-    u8 c1, c2, c3, c4;
+    u16 c1, c2, c3, c4;
     int fg0, bg0, fg, bg;
 
     dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx;
@@ -295,7 +295,7 @@
 
     while (count--)
 	if (xx&3 || count < 3) {	/* Slow version */
-	    c1 = *s++;
+	    c1 = *s++ & p->charmask;
 	    dest1 = dest0++;
 	    xx++;
 
@@ -322,10 +322,10 @@
 		dest1 += p->next_plane;
 	    } while (--i);
 	} else {			/* Fast version */
-	    c1 = s[0];
-	    c2 = s[1];
-	    c3 = s[2];
-	    c4 = s[3];
+	    c1 = s[0] & p->charmask;
+	    c2 = s[1] & p->charmask;
+	    c3 = s[2] & p->charmask;
+	    c4 = s[3] & p->charmask;
 
 	    dest1 = dest0;
 	    cdat10 = p->fontdata+c1*p->fontheight;
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-afb.h linux/drivers/video/fbcon-afb.h
--- v2.1.111/linux/drivers/video/fbcon-afb.h	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-afb.h	Sun Jul 26 14:40:19 1998
@@ -2,8 +2,6 @@
      *  Amiga bitplanes (afb)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_AFB_MODULE)
 #define FBCON_HAS_AFB
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb16.c linux/drivers/video/fbcon-cfb16.c
--- v2.1.111/linux/drivers/video/fbcon-cfb16.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-cfb16.c	Sun Jul 26 14:40:19 1998
@@ -47,23 +47,34 @@
     int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
     u8 *src, *dst;
 
-    if (sx == 0 && dx == 0 && width * 16 == bytes)
+    if (sx == 0 && dx == 0 && width * p->fontwidth * 2 == bytes) {
 	mymemmove(p->screen_base + dy * linesize,
 		  p->screen_base + sy * linesize,
 		  height * linesize);
-    else if (dy < sy || (dy == sy && dx < sx)) {
-	src = p->screen_base + sy * linesize + sx * 16;
-	dst = p->screen_base + dy * linesize + dx * 16;
-	for (rows = height * p->fontheight ; rows-- ;) {
-	    mymemmove(dst, src, width * 16);
+	return;
+    }
+    if (p->fontwidthlog) {
+	sx <<= p->fontwidthlog+1;
+	dx <<= p->fontwidthlog+1;
+	width <<= p->fontwidthlog+1;
+    } else {
+	sx *= p->fontwidth*2;
+	dx *= p->fontwidth*2;
+	width *= p->fontwidth*2;
+    }
+    if (dy < sy || (dy == sy && dx < sx)) {
+	src = p->screen_base + sy * linesize + sx;
+	dst = p->screen_base + dy * linesize + dx;
+	for (rows = height * p->fontheight; rows--;) {
+	    mymemmove(dst, src, width);
 	    src += bytes;
 	    dst += bytes;
 	}
     } else {
-	src = p->screen_base + (sy+height) * linesize + sx * 16 - bytes;
-	dst = p->screen_base + (dy+height) * linesize + dx * 16 - bytes;
-	for (rows = height * p->fontheight ; rows-- ;) {
-	    mymemmove(dst, src, width * 16);
+	src = p->screen_base + (sy+height) * linesize + sx - bytes;
+	dst = p->screen_base + (dy+height) * linesize + dx - bytes;
+	for (rows = height * p->fontheight; rows--;) {
+	    mymemmove(dst, src, width);
 	    src -= bytes;
 	    dst -= bytes;
 	}
@@ -77,29 +88,26 @@
     int bytes = p->next_line, lines = height * p->fontheight, rows, i;
     u32 bgx;
 
-    dest = p->screen_base + sy * p->fontheight * bytes + sx * 16;
+    dest = p->screen_base + sy * p->fontheight * bytes + sx * p->fontwidth * 2;
 
     bgx = fbcon_cfb16_cmap[attr_bgcol_ec(p, conp)];
     bgx |= (bgx << 16);
 
-    if (sx == 0 && width * 16 == bytes)
-	for (i = 0 ; i < lines * width ; i++) {
+    width *= p->fontwidth/4;
+    if (sx == 0 && width * 8 == bytes)
+	for (i = 0; i < lines * width; i++) {
 	    ((u32 *)dest)[0] = bgx;
 	    ((u32 *)dest)[1] = bgx;
-	    ((u32 *)dest)[2] = bgx;
-	    ((u32 *)dest)[3] = bgx;
-	    dest += 16;
+	    dest += 8;
 	}
     else {
 	dest0 = dest;
-	for (rows = lines; rows-- ; dest0 += bytes) {
+	for (rows = lines; rows--; dest0 += bytes) {
 	    dest = dest0;
-	    for (i = 0 ; i < width ; i++) {
+	    for (i = 0; i < width; i++) {
 		((u32 *)dest)[0] = bgx;
 		((u32 *)dest)[1] = bgx;
-		((u32 *)dest)[2] = bgx;
-		((u32 *)dest)[3] = bgx;
-		dest += 16;
+		dest += 8;
 	    }
 	}
     }
@@ -108,12 +116,11 @@
 void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c, int yy,
 		      int xx)
 {
-    u8 *dest, *cdat;
+    u8 *dest, *cdat, bits;
     int bytes = p->next_line, rows;
     u32 eorx, fgx, bgx;
 
-    dest = p->screen_base + yy * p->fontheight * bytes + xx * 16;
-    cdat = p->fontdata + (c & 0xff) * p->fontheight;
+    dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 2;
 
     fgx = fbcon_cfb16_cmap[attr_fgcol(p, c)];
     bgx = fbcon_cfb16_cmap[attr_bgcol(p, c)];
@@ -121,41 +128,112 @@
     bgx |= (bgx << 16);
     eorx = fgx ^ bgx;
 
-    for (rows = p->fontheight ; rows-- ; dest += bytes) {
-	u8 bits = *cdat++;
-	((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
-	((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
-	((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
-	((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+    switch (p->fontwidth) {
+    case 4:
+    case 8:
+#endif
+	cdat = p->fontdata + (c & p->charmask) * p->fontheight;
+	for (rows = p->fontheight; rows--; dest += bytes) {
+	    bits = *cdat++;
+	    ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+	    ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+	    if (p->fontwidth == 8)
+#endif
+	    {
+		((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+		((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+	    }
+	}
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+	break;
+    case 12:
+    case 16:
+	cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1);
+	for (rows = p->fontheight; rows--; dest += bytes) {
+	    bits = *cdat++;
+	    ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+	    ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+	    ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+	    ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+	    bits = *cdat++;
+	    ((u32 *)dest)[4] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+	    ((u32 *)dest)[5] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+	    if (p->fontwidth == 16) {
+		((u32 *)dest)[6] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+		((u32 *)dest)[7] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+	    }
+	}
+	break;
     }
+#endif
 }
 
-void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p, 
+void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p,
 		       const unsigned short *s, int count, int yy, int xx)
 {
-    u8 *cdat, c, *dest, *dest0;
+    u8 *cdat, *dest, *dest0;
+    u16 c;
     int rows, bytes = p->next_line;
     u32 eorx, fgx, bgx;
 
-    dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 16;
+    dest0 = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 2;
     fgx = fbcon_cfb16_cmap[attr_fgcol(p, *s)];
     bgx = fbcon_cfb16_cmap[attr_bgcol(p, *s)];
     fgx |= (fgx << 16);
     bgx |= (bgx << 16);
     eorx = fgx ^ bgx;
-    while (count--) {
-	c = *s++;
-	cdat = p->fontdata + c * p->fontheight;
 
-	for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
-	    u8 bits = *cdat++;
-	    ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
-	    ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
-	    ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
-	    ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+    switch (p->fontwidth) {
+    case 4:
+    case 8:
+#endif
+	while (count--) {
+	    c = *s++ & p->charmask;
+	    cdat = p->fontdata + c * p->fontheight;
+	    for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) {
+		u8 bits = *cdat++;
+		((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+		((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+		if (p->fontwidth == 8)
+#endif
+		{
+		
+		    ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+		    ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+		}
+	    }
+	    dest0 += p->fontwidth*2;;
+	}
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+	break;
+    case 12:
+    case 16:
+	while (count--) {
+	    c = *s++ & p->charmask;
+	    cdat = p->fontdata + (c * p->fontheight << 1);
+	    for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) {
+		u8 bits = *cdat++;
+		((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+		((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+		((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+		((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+		bits = *cdat++;
+		((u32 *)dest)[4] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
+		((u32 *)dest)[5] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+		if (p->fontwidth == 16) {
+		    ((u32 *)dest)[6] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
+		    ((u32 *)dest)[7] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+		}
+	    }
+	    dest0 += p->fontwidth*2;
 	}
-	dest0 += 16;
+	break;
     }
+#endif
 }
 
 void fbcon_cfb16_revc(struct display *p, int xx, int yy)
@@ -163,12 +241,60 @@
     u8 *dest;
     int bytes = p->next_line, rows;
 
-    dest = p->screen_base + yy * p->fontheight * bytes + xx * 16;
-    for (rows = p->fontheight ; rows-- ; dest += bytes) {
-	((u32 *)dest)[0] ^= 0xffffffff;
-	((u32 *)dest)[1] ^= 0xffffffff;
-	((u32 *)dest)[2] ^= 0xffffffff;
-	((u32 *)dest)[3] ^= 0xffffffff;
+    dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth*2;
+    for (rows = p->fontheight; rows--; dest += bytes) {
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+	((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff;
+	((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+#else
+	switch (p->fontwidth) {
+	case 16:
+	    ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
+	    /* FALL THROUGH */
+	case 12:
+	    ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff;
+	    /* FALL THROUGH */
+	case 8:
+	    ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff;
+	    /* FALL THROUGH */
+	case 4:
+	    ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+	}
+#endif
+    }
+}
+
+void fbcon_cfb16_clear_margins(struct vc_data *conp, struct display *p)
+{
+    u8 *dest0;
+    u32 *dest;
+    int bytes = p->next_line;
+    u32 bgx;
+    int i, j;
+
+    unsigned int right_start = conp->vc_cols*p->fontwidth;
+    unsigned int right_width = p->var.xres_virtual-right_start;
+    unsigned int bottom_start = conp->vc_rows*p->fontheight;
+    unsigned int bottom_width = p->var.yres_virtual-bottom_start;
+
+    bgx = fbcon_cfb16_cmap[attr_bgcol_ec(p, conp)];
+    bgx |= (bgx << 16);
+
+    if (right_width) {
+	dest0 = p->screen_base+right_start*2;
+	for (i = 0; i < bottom_start; i++, dest0 += bytes) {
+	    for (j = 0, dest = (u32 *)dest0; j < right_width/2; j++)
+		*dest++ = bgx;
+	    if (right_width & 1)
+		*(u16 *)dest = bgx;
+	}
+    }
+    if (bottom_width) {
+	dest = (u32 *)(p->screen_base+bottom_start*bytes);
+	for (i = 0; i < bytes*bottom_width/4; i++)
+	    *dest++ = bgx;
+	if ((bytes*bottom_width) & 2)
+	    *(u16 *)dest = bgx;
     }
 }
 
@@ -179,7 +305,8 @@
 
 struct display_switch fbcon_cfb16 = {
     fbcon_cfb16_setup, fbcon_cfb16_bmove, fbcon_cfb16_clear, fbcon_cfb16_putc,
-    fbcon_cfb16_putcs, fbcon_cfb16_revc, NULL, NULL, NULL, FONTWIDTH(8)
+    fbcon_cfb16_putcs, fbcon_cfb16_revc, NULL, NULL, fbcon_cfb16_clear_margins,
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 
 
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb16.h linux/drivers/video/fbcon-cfb16.h
--- v2.1.111/linux/drivers/video/fbcon-cfb16.h	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-cfb16.h	Sun Jul 26 14:40:19 1998
@@ -2,8 +2,6 @@
      *  16 bpp packed pixel (cfb16)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB16_MODULE)
 #define FBCON_HAS_CFB16
@@ -26,3 +24,4 @@
 extern void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p,
 			      const unsigned short *s, int count, int yy, int xx);
 extern void fbcon_cfb16_revc(struct display *p, int xx, int yy);
+extern void fbcon_cfb16_clear_margins(struct vc_data *conp, struct display *p);
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb2.c linux/drivers/video/fbcon-cfb2.c
--- v2.1.111/linux/drivers/video/fbcon-cfb2.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-cfb2.c	Sun Jul 26 14:40:19 1998
@@ -129,7 +129,7 @@
 	u32 eorx,fgx,bgx;
 
 	dest = p->screen_base + yy * p->fontheight * bytes + xx * 2;
-	cdat = p->fontdata + (c & 0xff) * p->fontheight;
+	cdat = p->fontdata + (c & p->charmask) * p->fontheight;
 
 	fgx=3;/*attr_fgcol(p,c);*/
 	bgx=attr_bgcol(p,c);
@@ -150,7 +150,8 @@
 void fbcon_cfb2_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
 		      int count, int yy, int xx)
 {
-	u8 *cdat, c, *dest, *dest0;
+	u8 *cdat, *dest, *dest0;
+	u16 c;
 	int rows,bytes=p->next_line;
 	u32 eorx, fgx, bgx;
 
@@ -163,7 +164,7 @@
 	bgx |= (bgx << 4);
 	eorx = fgx ^ bgx;
 	while (count--) {
-		c = *s++;
+		c = *s++ & p->charmask;
 		cdat = p->fontdata + c * p->fontheight;
 
 		for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb2.h linux/drivers/video/fbcon-cfb2.h
--- v2.1.111/linux/drivers/video/fbcon-cfb2.h	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-cfb2.h	Sun Jul 26 14:40:19 1998
@@ -2,8 +2,6 @@
      *  2 bpp packed pixel (cfb2)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB2) || defined(CONFIG_FBCON_CFB2_MODULE)
 #define FBCON_HAS_CFB2
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb24.c linux/drivers/video/fbcon-cfb24.c
--- v2.1.111/linux/drivers/video/fbcon-cfb24.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-cfb24.c	Sun Jul 26 14:40:19 1998
@@ -37,29 +37,56 @@
     int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
     u8 *src, *dst;
 
-    if (sx == 0 && dx == 0 && width * 24 == bytes)
+    if (sx == 0 && dx == 0 && width * p->fontwidth * 3 == bytes) {
 	mymemmove(p->screen_base + dy * linesize,
 		  p->screen_base + sy * linesize,
 		  height * linesize);
-    else if (dy < sy || (dy == sy && dx < sx)) {
-	src = p->screen_base + sy * linesize + sx * 24;
-	dst = p->screen_base + dy * linesize + dx * 24;
-	for (rows = height * p->fontheight ; rows-- ;) {
-	    mymemmove(dst, src, width * 24);
+	return;
+    }
+    if (p->fontwidthlog) {
+	sx <<= p->fontwidthlog;
+	dx <<= p->fontwidthlog;
+	width <<= p->fontwidthlog;
+    } else {
+	sx *= p->fontwidth;
+	dx *= p->fontwidth;
+	width *= p->fontwidth;
+    }
+    sx *= 3; dx *= 3; width *= 3;
+    if (dy < sy || (dy == sy && dx < sx)) {
+	src = p->screen_base + sy * linesize + sx;
+	dst = p->screen_base + dy * linesize + dx;
+	for (rows = height * p->fontheight; rows--;) {
+	    mymemmove(dst, src, width);
 	    src += bytes;
 	    dst += bytes;
 	}
     } else {
-	src = p->screen_base + (sy+height) * linesize + sx * 24 - bytes;
-	dst = p->screen_base + (dy+height) * linesize + dx * 24 - bytes;
-	for (rows = height * p->fontheight ; rows-- ;) {
-	    mymemmove(dst, src, width * 24);
+	src = p->screen_base + (sy+height) * linesize + sx - bytes;
+	dst = p->screen_base + (dy+height) * linesize + dx - bytes;
+	for (rows = height * p->fontheight; rows--;) {
+	    mymemmove(dst, src, width);
 	    src -= bytes;
 	    dst -= bytes;
 	}
     }
 }
 
+static inline void store4pixels(u32 d1, u32 d2, u32 d3, u32 d4, u32 *dest)
+{
+#if defined(__BIG_ENDIAN)
+    *dest++ = (d1<<8) | (d2>>16);
+    *dest++ = (d2<<16) | (d3>>8);
+    *dest++ = (d3<<24) | d4;
+#elif defined(__LITTLE_ENDIAN)
+    *dest++ = (d1<<8) | (d2>>16);
+    *dest++ = (d2<<16) | (d3>>8);
+    *dest++ = (d3<<24) | d4;
+#else
+#error FIXME: No endianness??
+#endif
+}
+
 void fbcon_cfb24_clear(struct vc_data *conp, struct display *p, int sy, int sx,
 		       int height, int width)
 {
@@ -67,112 +94,139 @@
     int bytes = p->next_line, lines = height * p->fontheight, rows, i;
     u32 bgx;
 
-    dest = p->screen_base + sy * p->fontheight * bytes + sx * 24;
+    dest = p->screen_base + sy * p->fontheight * bytes + sx * p->fontwidth * 3;
 
     bgx = fbcon_cfb24_cmap[attr_bgcol_ec(p, conp)];
 
-    if (sx == 0 && width * 24 == bytes)
-	for (i = 0 ; i < lines * width ; i++) {
-	    ((u32 *)dest)[0] = bgx;
-	    ((u32 *)dest)[1] = bgx;
-	    ((u32 *)dest)[2] = bgx;
-	    ((u32 *)dest)[3] = bgx;
-	    ((u32 *)dest)[4] = bgx;
-	    ((u32 *)dest)[5] = bgx;
-	    dest += 24;
+    width *= p->fontwidth/4;
+    if (sx == 0 && width * 12 == bytes)
+	for (i = 0; i < lines * width; i++) {
+	    store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest);
+	    dest += 12;
 	}
     else {
 	dest0 = dest;
-	for (rows = lines; rows-- ; dest0 += bytes) {
+	for (rows = lines; rows--; dest0 += bytes) {
 	    dest = dest0;
-	    for (i = 0 ; i < width ; i++) {
-		((u32 *)dest)[0] = bgx;
-		((u32 *)dest)[1] = bgx;
-		((u32 *)dest)[2] = bgx;
-		((u32 *)dest)[3] = bgx;
-		((u32 *)dest)[4] = bgx;
-		((u32 *)dest)[5] = bgx;
-		dest += 24;
+	    for (i = 0; i < width; i++) {
+		store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest);
+		dest += 12;
 	    }
 	}
     }
 }
 
-static inline void store4pixels(u32 d1, u32 d2, u32 d3, u32 d4, u32 *dest)
-{
-#if defined(__BIG_ENDIAN)
-    *dest++ = (d1<<8) | (d2>>16);
-    *dest++ = (d2<<16) | (d3>>8);
-    *dest++ = (d3<<24) | d4;
-#elif defined(__LITTLE_ENDIAN)
-    *dest++ = (d1<<8) | (d2>>16);
-    *dest++ = (d2<<16) | (d3>>8);
-    *dest++ = (d3<<24) | d4;
-#else
-#error FIXME: No endianness??
-#endif
-}
-
 void fbcon_cfb24_putc(struct vc_data *conp, struct display *p, int c, int yy,
 		      int xx)
 {
-    u8 *dest, *cdat;
+    u8 *dest, *cdat, bits;
     int bytes = p->next_line, rows;
-    u32 eorx, fgx, bgx;
+    u32 eorx, fgx, bgx, d1, d2, d3, d4;
 
-    dest = p->screen_base + yy * p->fontheight * bytes + xx * 24;
-    cdat = p->fontdata + (c & 0xff) * p->fontheight;
+    dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 3;
+    if (p->fontwidth <= 8)
+	cdat = p->fontdata + (c & p->charmask) * p->fontheight;
+    else
+	cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1);
 
     fgx = fbcon_cfb24_cmap[attr_fgcol(p, c)];
     bgx = fbcon_cfb24_cmap[attr_bgcol(p, c)];
     eorx = fgx ^ bgx;
 
-    for (rows = p->fontheight ; rows-- ; dest += bytes) {
-	u8 bits = *cdat++;
-	u32 d1, d2, d3, d4;
+    for (rows = p->fontheight; rows--; dest += bytes) {
+	bits = *cdat++;
 	d1 = (-(bits >> 7) & eorx) ^ bgx;
 	d2 = (-(bits >> 6 & 1) & eorx) ^ bgx;
 	d3 = (-(bits >> 5 & 1) & eorx) ^ bgx;
 	d4 = (-(bits >> 4 & 1) & eorx) ^ bgx;
 	store4pixels(d1, d2, d3, d4, (u32 *)dest);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+	if (p->fontwidth < 8)
+	    continue;
+#endif
 	d1 = (-(bits >> 3 & 1) & eorx) ^ bgx;
 	d2 = (-(bits >> 2 & 1) & eorx) ^ bgx;
 	d3 = (-(bits >> 1 & 1) & eorx) ^ bgx;
 	d4 = (-(bits & 1) & eorx) ^ bgx;
 	store4pixels(d1, d2, d3, d4, (u32 *)(dest+12));
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+	if (p->fontwidth < 12)
+	    continue;
+	bits = *cdat++;
+	d1 = (-(bits >> 7) & eorx) ^ bgx;
+	d2 = (-(bits >> 6 & 1) & eorx) ^ bgx;
+	d3 = (-(bits >> 5 & 1) & eorx) ^ bgx;
+	d4 = (-(bits >> 4 & 1) & eorx) ^ bgx;
+	store4pixels(d1, d2, d3, d4, (u32 *)(dest+24));
+	if (p->fontwidth < 16)
+	    continue;
+	d1 = (-(bits >> 3 & 1) & eorx) ^ bgx;
+	d2 = (-(bits >> 2 & 1) & eorx) ^ bgx;
+	d3 = (-(bits >> 1 & 1) & eorx) ^ bgx;
+	d4 = (-(bits & 1) & eorx) ^ bgx;
+	store4pixels(d1, d2, d3, d4, (u32 *)(dest+32));
+#endif
     }
 }
 
-void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p, 
+void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p,
 		       const unsigned short *s, int count, int yy, int xx)
 {
-    u8 *cdat, c, *dest, *dest0;
+    u8 *cdat, *dest, *dest0, bits;
+    u16 c;
     int rows, bytes = p->next_line;
-    u32 eorx, fgx, bgx;
+    u32 eorx, fgx, bgx, d1, d2, d3, d4;
 
-    dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 24;
+    dest0 = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 3;
     fgx = fbcon_cfb24_cmap[attr_fgcol(p, *s)];
     bgx = fbcon_cfb24_cmap[attr_bgcol(p, *s)];
     eorx = fgx ^ bgx;
     while (count--) {
-	c = *s++;
+	c = *s++ & p->charmask;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
 	cdat = p->fontdata + c * p->fontheight;
-
-	for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
-	    u8 bits = *cdat++;
-	    u32 d1, d2, d3, d4;
+#else
+	if (p->fontwidth <= 8)
+	    cdat = p->fontdata + c * p->fontheight;
+	  
+	else
+	    cdat = p->fontdata + (c * p->fontheight << 1);
+#endif
+	for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) {
+	    bits = *cdat++;
 	    d1 = (-(bits >> 7) & eorx) ^ bgx;
 	    d2 = (-(bits >> 6 & 1) & eorx) ^ bgx;
 	    d3 = (-(bits >> 5 & 1) & eorx) ^ bgx;
 	    d4 = (-(bits >> 4 & 1) & eorx) ^ bgx;
 	    store4pixels(d1, d2, d3, d4, (u32 *)dest);
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+	    if (p->fontwidth < 8)
+		continue;
+#endif
 	    d1 = (-(bits >> 3 & 1) & eorx) ^ bgx;
 	    d2 = (-(bits >> 2 & 1) & eorx) ^ bgx;
 	    d3 = (-(bits >> 1 & 1) & eorx) ^ bgx;
 	    d4 = (-(bits & 1) & eorx) ^ bgx;
 	    store4pixels(d1, d2, d3, d4, (u32 *)(dest+12));
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+	    if (p->fontwidth < 12)
+		continue;
+	    bits = *cdat++;
+	    d1 = (-(bits >> 7) & eorx) ^ bgx;
+	    d2 = (-(bits >> 6 & 1) & eorx) ^ bgx;
+	    d3 = (-(bits >> 5 & 1) & eorx) ^ bgx;
+	    d4 = (-(bits >> 4 & 1) & eorx) ^ bgx;
+	    store4pixels(d1, d2, d3, d4, (u32 *)(dest+24));
+	    if (p->fontwidth < 16)
+		continue;
+	    d1 = (-(bits >> 3 & 1) & eorx) ^ bgx;
+	    d2 = (-(bits >> 2 & 1) & eorx) ^ bgx;
+	    d3 = (-(bits >> 1 & 1) & eorx) ^ bgx;
+	    d4 = (-(bits & 1) & eorx) ^ bgx;
+	    store4pixels(d1, d2, d3, d4, (u32 *)(dest+32));
+#endif
 	}
-	dest0 += 24;
+	dest0 += p->fontwidth*3;
     }
 }
 
@@ -181,14 +235,60 @@
     u8 *dest;
     int bytes = p->next_line, rows;
 
-    dest = p->screen_base + yy * p->fontheight * bytes + xx * 24;
-    for (rows = p->fontheight ; rows-- ; dest += bytes) {
-	((u32 *)dest)[0] ^= 0xffffffff;
-	((u32 *)dest)[1] ^= 0xffffffff;
-	((u32 *)dest)[2] ^= 0xffffffff;
-	((u32 *)dest)[3] ^= 0xffffffff;
-	((u32 *)dest)[4] ^= 0xffffffff;
+    dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 3;
+    for (rows = p->fontheight; rows--; dest += bytes) {
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+	((u32 *)dest)[3] ^= 0xffffffff; ((u32 *)dest)[4] ^= 0xffffffff;
 	((u32 *)dest)[5] ^= 0xffffffff;
+	((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+	((u32 *)dest)[2] ^= 0xffffffff;
+#else
+	switch (p->fontwidth) {
+	case 16:
+	    ((u32 *)dest)[9] ^= 0xffffffff; ((u32 *)dest)[10] ^= 0xffffffff;
+	    ((u32 *)dest)[11] ^= 0xffffffff;	/* FALL THROUGH */
+	case 12:
+	    ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
+	    ((u32 *)dest)[8] ^= 0xffffffff;	/* FALL THROUGH */
+	case 8:
+	    ((u32 *)dest)[3] ^= 0xffffffff; ((u32 *)dest)[4] ^= 0xffffffff;
+	    ((u32 *)dest)[5] ^= 0xffffffff;	/* FALL THROUGH */
+	case 4:
+	    ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+	    ((u32 *)dest)[2] ^= 0xffffffff;
+	}
+#endif
+    }
+}
+
+void fbcon_cfb24_clear_margins(struct vc_data *conp, struct display *p)
+{
+    u8 *dest0, *dest;
+    int bytes = p->next_line;
+    u32 bgx;
+    int i, j;
+
+    unsigned int right_start = conp->vc_cols*p->fontwidth;
+    unsigned int right_width = p->var.xres_virtual-right_start;
+    unsigned int bottom_start = conp->vc_rows*p->fontheight;
+    unsigned int bottom_width = p->var.yres_virtual-bottom_start;
+
+    bgx = fbcon_cfb24_cmap[attr_bgcol_ec(p, conp)];
+
+    if (right_width) {
+	dest0 = p->screen_base+right_start*3;
+	for (i = 0; i < bottom_start; i++, dest0 += bytes)
+	    for (j = 0, dest = dest0; j < right_width/4; j++) {
+		store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest);
+		dest += 12;
+	    }
+    }
+    if (bottom_width) {
+	dest = p->screen_base+bottom_start*bytes;
+	for (i = 0; i < bytes*bottom_width/12; i++) {
+	    store4pixels(bgx, bgx, bgx, bgx, (u32 *)dest);
+	    dest += 12;
+	}
     }
 }
 
@@ -199,7 +299,8 @@
 
 struct display_switch fbcon_cfb24 = {
     fbcon_cfb24_setup, fbcon_cfb24_bmove, fbcon_cfb24_clear, fbcon_cfb24_putc,
-    fbcon_cfb24_putcs, fbcon_cfb24_revc, NULL, NULL, NULL, FONTWIDTH(8)
+    fbcon_cfb24_putcs, fbcon_cfb24_revc, NULL, NULL, fbcon_cfb24_clear_margins,
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 
 
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb24.h linux/drivers/video/fbcon-cfb24.h
--- v2.1.111/linux/drivers/video/fbcon-cfb24.h	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-cfb24.h	Sun Jul 26 14:40:19 1998
@@ -2,8 +2,6 @@
      *  24 bpp packed pixel (cfb24)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB24) || defined(CONFIG_FBCON_CFB24_MODULE)
 #define FBCON_HAS_CFB24
@@ -26,3 +24,4 @@
 extern void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p,
 			      const unsigned short *s, int count, int yy, int xx);
 extern void fbcon_cfb24_revc(struct display *p, int xx, int yy);
+extern void fbcon_cfb24_clear_margins(struct vc_data *conp, struct display *p);
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb32.c linux/drivers/video/fbcon-cfb32.c
--- v2.1.111/linux/drivers/video/fbcon-cfb32.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-cfb32.c	Sun Jul 26 14:40:19 1998
@@ -37,23 +37,34 @@
     int bytes = p->next_line, linesize = bytes * p->fontheight, rows;
     u8 *src, *dst;
 
-    if (sx == 0 && dx == 0 && width * 32 == bytes)
+    if (sx == 0 && dx == 0 && width * p->fontwidth * 4 == bytes) {
 	mymemmove(p->screen_base + dy * linesize,
 		  p->screen_base + sy * linesize,
 		  height * linesize);
-    else if (dy < sy || (dy == sy && dx < sx)) {
-	src = p->screen_base + sy * linesize + sx * 32;
-	dst = p->screen_base + dy * linesize + dx * 32;
-	for (rows = height * p->fontheight ; rows-- ;) {
-	    mymemmove(dst, src, width * 32);
+	return;
+    }
+    if (p->fontwidthlog) {
+	sx <<= p->fontwidthlog+2;
+	dx <<= p->fontwidthlog+2;
+	width <<= p->fontwidthlog+2;
+    } else {
+	sx *= p->fontwidth*4;
+	dx *= p->fontwidth*4;
+	width *= p->fontwidth*4;
+    }
+    if (dy < sy || (dy == sy && dx < sx)) {
+	src = p->screen_base + sy * linesize + sx;
+	dst = p->screen_base + dy * linesize + dx;
+	for (rows = height * p->fontheight; rows--;) {
+	    mymemmove(dst, src, width);
 	    src += bytes;
 	    dst += bytes;
 	}
     } else {
-	src = p->screen_base + (sy+height) * linesize + sx * 32 - bytes;
-	dst = p->screen_base + (dy+height) * linesize + dx * 32 - bytes;
-	for (rows = height * p->fontheight ; rows-- ;) {
-	    mymemmove(dst, src, width * 32);
+	src = p->screen_base + (sy+height) * linesize + sx - bytes;
+	dst = p->screen_base + (dy+height) * linesize + dx - bytes;
+	for (rows = height * p->fontheight; rows--;) {
+	    mymemmove(dst, src, width);
 	    src -= bytes;
 	    dst -= bytes;
 	}
@@ -67,36 +78,29 @@
     int bytes = p->next_line, lines = height * p->fontheight, rows, i;
     u32 bgx;
 
-    dest = p->screen_base + sy * p->fontheight * bytes + sx * 32;
+    dest = p->screen_base + sy * p->fontheight * bytes + sx * p->fontwidth * 4;
 
     bgx = fbcon_cfb32_cmap[attr_bgcol_ec(p, conp)];
 
-    if (sx == 0 && width * 32 == bytes)
-	for (i = 0 ; i < lines * width ; i++) {
+    width *= p->fontwidth/4;
+    if (sx == 0 && width * 16 == bytes)
+	for (i = 0; i < lines * width; i++) {
 	    ((u32 *)dest)[0] = bgx;
 	    ((u32 *)dest)[1] = bgx;
 	    ((u32 *)dest)[2] = bgx;
 	    ((u32 *)dest)[3] = bgx;
-	    ((u32 *)dest)[4] = bgx;
-	    ((u32 *)dest)[5] = bgx;
-	    ((u32 *)dest)[6] = bgx;
-	    ((u32 *)dest)[7] = bgx;
-	    dest += 32;
+	    dest += 16;
 	}
     else {
 	dest0 = dest;
-	for (rows = lines; rows-- ; dest0 += bytes) {
+	for (rows = lines; rows--; dest0 += bytes) {
 	    dest = dest0;
-	    for (i = 0 ; i < width ; i++) {
+	    for (i = 0; i < width; i++) {
 		((u32 *)dest)[0] = bgx;
 		((u32 *)dest)[1] = bgx;
 		((u32 *)dest)[2] = bgx;
 		((u32 *)dest)[3] = bgx;
-		((u32 *)dest)[4] = bgx;
-		((u32 *)dest)[5] = bgx;
-		((u32 *)dest)[6] = bgx;
-		((u32 *)dest)[7] = bgx;
-		dest += 32;
+		dest += 16;
 	    }
 	}
     }
@@ -105,57 +109,108 @@
 void fbcon_cfb32_putc(struct vc_data *conp, struct display *p, int c, int yy,
 		      int xx)
 {
-    u8 *dest, *cdat;
+    u8 *dest, *cdat, bits;
     int bytes = p->next_line, rows;
     u32 eorx, fgx, bgx;
 
-    dest = p->screen_base + yy * p->fontheight * bytes + xx * 32;
-    cdat = p->fontdata + (c & 0xff) * p->fontheight;
-
+    dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 4;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+    cdat = p->fontdata + (c & p->charmask) * p->fontheight;
+#else
+    if (p->fontwidth <= 8)
+	cdat = p->fontdata + (c & p->charmask) * p->fontheight;
+    else
+	cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1);
+#endif
     fgx = fbcon_cfb32_cmap[attr_fgcol(p, c)];
     bgx = fbcon_cfb32_cmap[attr_bgcol(p, c)];
     eorx = fgx ^ bgx;
 
-    for (rows = p->fontheight ; rows-- ; dest += bytes) {
-	u8 bits = *cdat++;
+    for (rows = p->fontheight; rows--; dest += bytes) {
+	bits = *cdat++;
 	((u32 *)dest)[0] = (-(bits >> 7) & eorx) ^ bgx;
 	((u32 *)dest)[1] = (-(bits >> 6 & 1) & eorx) ^ bgx;
 	((u32 *)dest)[2] = (-(bits >> 5 & 1) & eorx) ^ bgx;
 	((u32 *)dest)[3] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+	if (p->fontwidth < 8)
+	    continue;
+#endif
 	((u32 *)dest)[4] = (-(bits >> 3 & 1) & eorx) ^ bgx;
 	((u32 *)dest)[5] = (-(bits >> 2 & 1) & eorx) ^ bgx;
 	((u32 *)dest)[6] = (-(bits >> 1 & 1) & eorx) ^ bgx;
 	((u32 *)dest)[7] = (-(bits & 1) & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+	if (p->fontwidth < 12)
+	    continue;
+	bits = *cdat++;
+	((u32 *)dest)[8] = (-(bits >> 7) & eorx) ^ bgx;
+	((u32 *)dest)[9] = (-(bits >> 6 & 1) & eorx) ^ bgx;
+	((u32 *)dest)[10] = (-(bits >> 5 & 1) & eorx) ^ bgx;
+	((u32 *)dest)[11] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+	if (p->fontwidth < 16)
+	    continue;
+	((u32 *)dest)[12] = (-(bits >> 3 & 1) & eorx) ^ bgx;
+	((u32 *)dest)[13] = (-(bits >> 2 & 1) & eorx) ^ bgx;
+	((u32 *)dest)[14] = (-(bits >> 1 & 1) & eorx) ^ bgx;
+	((u32 *)dest)[15] = (-(bits & 1) & eorx) ^ bgx;
+#endif
     }
 }
 
-void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p, 
+void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p,
 		       const unsigned short *s, int count, int yy, int xx)
 {
-    u8 *cdat, c, *dest, *dest0;
+    u8 *cdat, *dest, *dest0, bits;
+    u16 c;
     int rows, bytes = p->next_line;
     u32 eorx, fgx, bgx;
 
-    dest0 = p->screen_base + yy * p->fontheight * bytes + xx * 32;
+    dest0 = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 4;
     fgx = fbcon_cfb32_cmap[attr_fgcol(p, *s)];
     bgx = fbcon_cfb32_cmap[attr_bgcol(p, *s)];
     eorx = fgx ^ bgx;
     while (count--) {
-	c = *s++;
+	c = *s++ & p->charmask;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
 	cdat = p->fontdata + c * p->fontheight;
-
-	for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
-	    u8 bits = *cdat++;
+#else
+	if (p->fontwidth <= 8)
+	    cdat = p->fontdata + c * p->fontheight;
+	else
+	    cdat = p->fontdata + (c * p->fontheight << 1);
+#endif
+	for (rows = p->fontheight, dest = dest0; rows--; dest += bytes) {
+	    bits = *cdat++;
 	    ((u32 *)dest)[0] = (-(bits >> 7) & eorx) ^ bgx;
 	    ((u32 *)dest)[1] = (-(bits >> 6 & 1) & eorx) ^ bgx;
 	    ((u32 *)dest)[2] = (-(bits >> 5 & 1) & eorx) ^ bgx;
 	    ((u32 *)dest)[3] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+	    if (p->fontwidth < 8)
+		continue;
+#endif
 	    ((u32 *)dest)[4] = (-(bits >> 3 & 1) & eorx) ^ bgx;
 	    ((u32 *)dest)[5] = (-(bits >> 2 & 1) & eorx) ^ bgx;
 	    ((u32 *)dest)[6] = (-(bits >> 1 & 1) & eorx) ^ bgx;
 	    ((u32 *)dest)[7] = (-(bits & 1) & eorx) ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+	    if (p->fontwidth < 12)
+		continue;
+	    bits = *cdat++;
+	    ((u32 *)dest)[8] = (-(bits >> 7) & eorx) ^ bgx;
+	    ((u32 *)dest)[9] = (-(bits >> 6 & 1) & eorx) ^ bgx;
+	    ((u32 *)dest)[10] = (-(bits >> 5 & 1) & eorx) ^ bgx;
+	    ((u32 *)dest)[11] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+	    if (p->fontwidth < 16)
+		continue;
+	    ((u32 *)dest)[12] = (-(bits >> 3 & 1) & eorx) ^ bgx;
+	    ((u32 *)dest)[13] = (-(bits >> 2 & 1) & eorx) ^ bgx;
+	    ((u32 *)dest)[14] = (-(bits >> 1 & 1) & eorx) ^ bgx;
+	    ((u32 *)dest)[15] = (-(bits & 1) & eorx) ^ bgx;
+#endif
 	}
-	dest0 += 32;
+	dest0 += p->fontwidth*4;
     }
 }
 
@@ -164,16 +219,61 @@
     u8 *dest;
     int bytes = p->next_line, rows;
 
-    dest = p->screen_base + yy * p->fontheight * bytes + xx * 32;
-    for (rows = p->fontheight ; rows-- ; dest += bytes) {
-	((u32 *)dest)[0] ^= 0xffffffff;
-	((u32 *)dest)[1] ^= 0xffffffff;
-	((u32 *)dest)[2] ^= 0xffffffff;
-	((u32 *)dest)[3] ^= 0xffffffff;
-	((u32 *)dest)[4] ^= 0xffffffff;
-	((u32 *)dest)[5] ^= 0xffffffff;
-	((u32 *)dest)[6] ^= 0xffffffff;
-	((u32 *)dest)[7] ^= 0xffffffff;
+    dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth * 4;
+    for (rows = p->fontheight; rows--; dest += bytes) {
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+	((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff;
+	((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
+	((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+	((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff;
+#else
+	switch (p->fontwidth) {
+	case 16:
+	    ((u32 *)dest)[12] ^= 0xffffffff; ((u32 *)dest)[13] ^= 0xffffffff;
+	    ((u32 *)dest)[14] ^= 0xffffffff; ((u32 *)dest)[15] ^= 0xffffffff;
+	    /* FALL THROUGH */
+	case 12:
+	    ((u32 *)dest)[8] ^= 0xffffffff; ((u32 *)dest)[9] ^= 0xffffffff;
+	    ((u32 *)dest)[10] ^= 0xffffffff; ((u32 *)dest)[11] ^= 0xffffffff;
+	    /* FALL THROUGH */
+	case 8:
+	    ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff;
+	    ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
+	    /* FALL THROUGH */
+	case 4:
+	    ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+	    ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff;
+	    /* FALL THROUGH */
+	}
+#endif
+    }
+}
+
+void fbcon_cfb32_clear_margins(struct vc_data *conp, struct display *p)
+{
+    u8 *dest0;
+    u32 *dest;
+    int bytes = p->next_line;
+    u32 bgx;
+    int i, j;
+
+    unsigned int right_start = conp->vc_cols*p->fontwidth;
+    unsigned int right_width = p->var.xres_virtual-right_start;
+    unsigned int bottom_start = conp->vc_rows*p->fontheight;
+    unsigned int bottom_width = p->var.yres_virtual-bottom_start;
+
+    bgx = fbcon_cfb32_cmap[attr_bgcol_ec(p, conp)];
+
+    if (right_width) {
+	dest0 = p->screen_base+right_start*4;
+	for (i = 0; i < bottom_start; i++, dest0 += bytes)
+	    for (j = 0, dest = (u32 *)dest0; j < right_width; j++)
+		*dest++ = bgx;
+    }
+    if (bottom_width) {
+	dest = (u32 *)(p->screen_base+bottom_start*bytes);
+	for (i = 0; i < bytes*bottom_width/4; i++)
+	    *dest++ = bgx;
     }
 }
 
@@ -184,7 +284,8 @@
 
 struct display_switch fbcon_cfb32 = {
     fbcon_cfb32_setup, fbcon_cfb32_bmove, fbcon_cfb32_clear, fbcon_cfb32_putc,
-    fbcon_cfb32_putcs, fbcon_cfb32_revc, NULL, NULL, NULL, FONTWIDTH(8)
+    fbcon_cfb32_putcs, fbcon_cfb32_revc, NULL, NULL, fbcon_cfb32_clear_margins,
+    FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 
 
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb32.h linux/drivers/video/fbcon-cfb32.h
--- v2.1.111/linux/drivers/video/fbcon-cfb32.h	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-cfb32.h	Sun Jul 26 14:40:19 1998
@@ -2,8 +2,6 @@
      *  32 bpp packed pixel (cfb32)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FBCON_CFB32_MODULE)
 #define FBCON_HAS_CFB32
@@ -26,3 +24,4 @@
 extern void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p,
 			      const unsigned short *s, int count, int yy, int xx);
 extern void fbcon_cfb32_revc(struct display *p, int xx, int yy);
+extern void fbcon_cfb32_clear_margins(struct vc_data *conp, struct display *p);
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb4.c linux/drivers/video/fbcon-cfb4.c
--- v2.1.111/linux/drivers/video/fbcon-cfb4.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-cfb4.c	Sun Jul 26 14:40:19 1998
@@ -131,7 +131,7 @@
 	u32 eorx,fgx,bgx;
 
 	dest = p->screen_base + yy * p->fontheight * bytes + xx * 4;
-	cdat = p->fontdata + (c & 0xff) * p->fontheight;
+	cdat = p->fontdata + (c & p->charmask) * p->fontheight;
 
 	fgx=15;/*attr_fgcol(p,c);*/
 	bgx=attr_bgcol(p,c);
@@ -152,7 +152,8 @@
 void fbcon_cfb4_putcs(struct vc_data *conp, struct display *p, 
 		      const unsigned short *s, int count, int yy, int xx)
 {
-	u8 *cdat, c, *dest, *dest0;
+	u8 *cdat, *dest, *dest0;
+	u16 c;
 	int rows,bytes=p->next_line;
 	u32 eorx, fgx, bgx;
 
@@ -167,7 +168,7 @@
 	bgx |= (bgx << 16);
 	eorx = fgx ^ bgx;
 	while (count--) {
-		c = *s++;
+		c = *s++ & p->charmask;
 		cdat = p->fontdata + c * p->fontheight;
 
 		for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb4.h linux/drivers/video/fbcon-cfb4.h
--- v2.1.111/linux/drivers/video/fbcon-cfb4.h	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-cfb4.h	Sun Jul 26 14:40:19 1998
@@ -2,8 +2,6 @@
      *  4 bpp packed pixel (cfb4)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB4) || defined(CONFIG_FBCON_CFB4_MODULE)
 #define FBCON_HAS_CFB4
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb8.c linux/drivers/video/fbcon-cfb8.c
--- v2.1.111/linux/drivers/video/fbcon-cfb8.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-cfb8.c	Sun Jul 26 14:40:19 1998
@@ -110,9 +110,9 @@
 
     dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth;
     if (p->fontwidth <= 8)
-	cdat = p->fontdata + (c & 0xff) * p->fontheight;
+	cdat = p->fontdata + (c & p->charmask) * p->fontheight;
     else
-	cdat = p->fontdata + ((c & 0xff) * p->fontheight << 1);
+	cdat = p->fontdata + ((c & p->charmask) * p->fontheight << 1);
 
     fgx=attr_fgcol(p,c);
     bgx=attr_bgcol(p,c);
@@ -122,16 +122,19 @@
     bgx |= (bgx << 16);
     eorx = fgx ^ bgx;
 
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
     switch (p->fontwidth) {
     case 4:
 	for (rows = p->fontheight ; rows-- ; dest += bytes)
 	    ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat++ >> 4] & eorx) ^ bgx;
         break;
     case 8:
+#endif
 	for (rows = p->fontheight ; rows-- ; dest += bytes) {
 	    ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
 	    ((u32 *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx;
         }
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
         break;
     case 12:
     case 16:
@@ -145,12 +148,14 @@
         }
         break;
     }
+#endif
 }
 
 void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p, 
 		      const unsigned short *s, int count, int yy, int xx)
 {
-    u8 *cdat, c, *dest, *dest0;
+    u8 *cdat, *dest, *dest0;
+    u16 c;
     int rows,bytes=p->next_line;
     u32 eorx, fgx, bgx;
 
@@ -162,10 +167,11 @@
     bgx |= (bgx << 8);
     bgx |= (bgx << 16);
     eorx = fgx ^ bgx;
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
     switch (p->fontwidth) {
     case 4:
 	while (count--) {
-	    c = *s++;
+	    c = *s++ & p->charmask;
 	    cdat = p->fontdata + c * p->fontheight;
 
 	    for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes)
@@ -174,8 +180,9 @@
         }
         break;
     case 8:
+#endif
 	while (count--) {
-	    c = *s++;
+	    c = *s++ & p->charmask;
 	    cdat = p->fontdata + c * p->fontheight;
 
 	    for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
@@ -184,11 +191,12 @@
 	    }
 	    dest0+=8;
         }
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
         break;
     case 12:
     case 16:
 	while (count--) {
-	    c = *s++;
+	    c = *s++ & p->charmask;
 	    cdat = p->fontdata + (c * p->fontheight << 1);
 
 	    for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
@@ -203,6 +211,7 @@
         }
         break;
     }
+#endif
 }
 
 void fbcon_cfb8_revc(struct display *p, int xx, int yy)
@@ -212,6 +221,10 @@
 
     dest = p->screen_base + yy * p->fontheight * bytes + xx * p->fontwidth;
     for (rows = p->fontheight ; rows-- ; dest += bytes) {
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+    	((u32 *)dest)[1] ^= 0x0f0f0f0f;
+    	((u32 *)dest)[0] ^= 0x0f0f0f0f;
+#else
     	switch (p->fontwidth) {
     	case 16: ((u32 *)dest)[3] ^= 0x0f0f0f0f; /* FALL THROUGH */
     	case 12: ((u32 *)dest)[2] ^= 0x0f0f0f0f; /* FALL THROUGH */
@@ -219,6 +232,7 @@
     	case 4: ((u32 *)dest)[0] ^= 0x0f0f0f0f;  /* FALL THROUGH */
     	default: break;
     	}
+#endif
     }
 }
 
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-cfb8.h linux/drivers/video/fbcon-cfb8.h
--- v2.1.111/linux/drivers/video/fbcon-cfb8.h	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-cfb8.h	Sun Jul 26 14:40:19 1998
@@ -2,8 +2,6 @@
      *  8 bpp packed pixel (cfb8)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FBCON_CFB8_MODULE)
 #define FBCON_HAS_CFB8
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-ilbm.c linux/drivers/video/fbcon-ilbm.c
--- v2.1.111/linux/drivers/video/fbcon-ilbm.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-ilbm.c	Sun Jul 26 14:40:19 1998
@@ -103,7 +103,7 @@
     int fg0, bg0, fg, bg;
 
     dest = p->screen_base+yy*p->fontheight*p->next_line+xx;
-    cdat = p->fontdata+(c&0xff)*p->fontheight;
+    cdat = p->fontdata+(c&p->charmask)*p->fontheight;
     fg0 = attr_fgcol(p,c);
     bg0 = attr_bgcol(p,c);
 
@@ -149,7 +149,7 @@
 {
     u8 *dest0, *dest, *cdat1, *cdat2, *cdat3, *cdat4;
     u_int rows, i;
-    u8 c1, c2, c3, c4;
+    u16 c1, c2, c3, c4;
     u32 d;
     int fg0, bg0, fg, bg;
 
@@ -159,7 +159,7 @@
 
     while (count--)
 	if (xx&3 || count < 3) {	/* Slow version */
-	    c1 = *s++;
+	    c1 = *s++ & p->charmask;
 	    dest = dest0++;
 	    xx++;
 
@@ -185,10 +185,10 @@
 		}
 	    }
 	} else {		/* Fast version */
-	    c1 = s[0];
-	    c2 = s[1];
-	    c3 = s[2];
-	    c4 = s[3];
+	    c1 = s[0] & p->charmask;
+	    c2 = s[1] & p->charmask;
+	    c3 = s[2] & p->charmask;
+	    c4 = s[3] & p->charmask;
 
 	    dest = dest0;
 	    cdat1 = p->fontdata+c1*p->fontheight;
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-ilbm.h linux/drivers/video/fbcon-ilbm.h
--- v2.1.111/linux/drivers/video/fbcon-ilbm.h	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-ilbm.h	Sun Jul 26 14:40:19 1998
@@ -2,8 +2,6 @@
      *  Amiga interleaved bitplanes (ilbm)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_ILBM) || defined(CONFIG_FBCON_ILBM_MODULE)  
 #define FBCON_HAS_ILBM 
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-iplan2p2.c linux/drivers/video/fbcon-iplan2p2.c
--- v2.1.111/linux/drivers/video/fbcon-iplan2p2.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-iplan2p2.c	Sun Jul 26 14:40:19 1998
@@ -307,7 +307,7 @@
     u16 eorx, fgx, bgx, fdx;
 
     dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*4 + (xx & 1);
-    cdat = p->fontdata + (c & 0xff) * p->fontheight;
+    cdat = p->fontdata + (c & p->charmask) * p->fontheight;
 
     fgx = expand2w(COLOR_2P(attr_fgcol(p,c)));
     bgx = expand2w(COLOR_2P(attr_bgcol(p,c)));
@@ -323,7 +323,8 @@
 			  const unsigned short *s, int count, int yy, int xx)
 {
     u8 *dest, *dest0;
-    u8 *cdat, c;
+    u8 *cdat;
+    u16 c;
     int rows;
     int bytes;
     u16 eorx, fgx, bgx, fdx;
@@ -335,7 +336,7 @@
     eorx = fgx ^ bgx;
 
     while (count--) {
-	c = *s++;
+	c = *s++ & p->charmask;
 	cdat  = p->fontdata + (c * p->fontheight);
 
 	for (rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-iplan2p2.h linux/drivers/video/fbcon-iplan2p2.h
--- v2.1.111/linux/drivers/video/fbcon-iplan2p2.h	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-iplan2p2.h	Sun Jul 26 14:40:19 1998
@@ -2,8 +2,6 @@
      *  Atari interleaved bitplanes (2 planes) (iplan2p2)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P2_MODULE)
 #define FBCON_HAS_IPLAN2P2
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-iplan2p4.c linux/drivers/video/fbcon-iplan2p4.c
--- v2.1.111/linux/drivers/video/fbcon-iplan2p4.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-iplan2p4.c	Sun Jul 26 14:40:19 1998
@@ -317,7 +317,7 @@
     u32 eorx, fgx, bgx, fdx;
 
     dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*8 + (xx & 1);
-    cdat = p->fontdata + (c & 0xff) * p->fontheight;
+    cdat = p->fontdata + (c & p->charmask) * p->fontheight;
 
     fgx = expand4l(attr_fgcol(p,c));
     bgx = expand4l(attr_bgcol(p,c));
@@ -333,7 +333,8 @@
 			  const unsigned short *s, int count, int yy, int xx)
 {
     u8 *dest, *dest0;
-    u8 *cdat, c;
+    u8 *cdat;
+    u16 c;
     int rows;
     int bytes;
     u32 eorx, fgx, bgx, fdx;
@@ -352,7 +353,7 @@
 	* cache :-(
 	*/
 
-	c = *s++;
+	c = *s++ & p->charmask;
 	cdat  = p->fontdata + (c * p->fontheight);
 
 	for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-iplan2p4.h linux/drivers/video/fbcon-iplan2p4.h
--- v2.1.111/linux/drivers/video/fbcon-iplan2p4.h	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-iplan2p4.h	Sun Jul 26 14:40:19 1998
@@ -2,8 +2,6 @@
      *  Atari interleaved bitplanes (4 planes) (iplan2p4)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_IPLAN2P4) || defined(CONFIG_FBCON_IPLAN2P4_MODULE)
 #define FBCON_HAS_IPLAN2P4
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-iplan2p8.c linux/drivers/video/fbcon-iplan2p8.c
--- v2.1.111/linux/drivers/video/fbcon-iplan2p8.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-iplan2p8.c	Sun Jul 26 14:40:19 1998
@@ -349,7 +349,7 @@
     u32 eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
 
     dest = p->screen_base + yy * p->fontheight * bytes + (xx>>1)*16 + (xx & 1);
-    cdat = p->fontdata + (c & 0xff) * p->fontheight;
+    cdat = p->fontdata + (c & p->charmask) * p->fontheight;
 
     expand8dl(attr_fgcol(p,c), &fgx1, &fgx2);
     expand8dl(attr_bgcol(p,c), &bgx1, &bgx2);
@@ -365,7 +365,8 @@
 			  const unsigned short *s, int count, int yy, int xx)
 {
     u8 *dest, *dest0;
-    u8 *cdat, c;
+    u8 *cdat;
+    u16 c;
     int rows;
     int bytes;
     u32 eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
@@ -387,7 +388,7 @@
 	* cache :-(
 	*/
 
-	c = *s++;
+	c = *s++ & p->charmask;
 	cdat  = p->fontdata + (c * p->fontheight);
 
 	for(rows = p->fontheight, dest = dest0; rows-- ; dest += bytes) {
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-iplan2p8.h linux/drivers/video/fbcon-iplan2p8.h
--- v2.1.111/linux/drivers/video/fbcon-iplan2p8.h	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-iplan2p8.h	Sun Jul 26 14:40:19 1998
@@ -2,8 +2,6 @@
      *  Atari interleaved bitplanes (8 planes) (iplan2p8)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_IPLAN2P8) || defined(CONFIG_FBCON_IPLAN2P8_MODULE)
 #define FBCON_HAS_IPLAN2P8
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-mac.c linux/drivers/video/fbcon-mac.c
--- v2.1.111/linux/drivers/video/fbcon-mac.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-mac.c	Sun Jul 26 14:40:19 1998
@@ -272,7 +272,7 @@
    u8 d;
    int j;
 
-   cdat = p->fontdata+(c&0xff)*p->fontheight;
+   cdat = p->fontdata+(c&p->charmask)*p->fontheight;
    bold = attr_bold(p,c);
    ch_reverse = attr_reverse(p,c);
    ch_underline = attr_underline(p,c);
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-mac.h linux/drivers/video/fbcon-mac.h
--- v2.1.111/linux/drivers/video/fbcon-mac.h	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-mac.h	Sun Jul 26 14:40:19 1998
@@ -2,8 +2,6 @@
      *  Mac variable bpp packed pixels (mac)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_MAC) || defined(CONFIG_FBCON_MAC_MODULE)
 #define FBCON_HAS_MAC
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-mfb.c linux/drivers/video/fbcon-mfb.c
--- v2.1.111/linux/drivers/video/fbcon-mfb.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-mfb.c	Sun Jul 26 14:40:19 1998
@@ -90,7 +90,7 @@
     u8 d;
 
     dest = p->screen_base+yy*p->fontheight*p->next_line+xx;
-    cdat = p->fontdata+(c&0xff)*p->fontheight;
+    cdat = p->fontdata+(c&p->charmask)*p->fontheight;
     bold = attr_bold(p,c);
     revs = attr_reverse(p,c);
     underl = attr_underline(p,c);
@@ -112,7 +112,8 @@
 {
     u8 *dest, *dest0, *cdat;
     u_int rows, bold, revs, underl;
-    u8 c, d;
+    u8 d;
+    u16 c;
 
     dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx;
     bold = attr_bold(p,*s);
@@ -120,7 +121,7 @@
     underl = attr_underline(p,*s);
 
     while (count--) {
-	c = *s++;
+	c = *s++ & p->charmask;
 	dest = dest0++;
 	cdat = p->fontdata+c*p->fontheight;
 	for (rows = p->fontheight; rows--; dest += p->next_line) {
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-mfb.h linux/drivers/video/fbcon-mfb.h
--- v2.1.111/linux/drivers/video/fbcon-mfb.h	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-mfb.h	Sun Jul 26 14:40:19 1998
@@ -2,8 +2,6 @@
      *  Monochrome (mfb)
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_MFB_MODULE)
 #define FBCON_HAS_MFB
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon-vga.h linux/drivers/video/fbcon-vga.h
--- v2.1.111/linux/drivers/video/fbcon-vga.h	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon-vga.h	Sun Jul 26 14:40:19 1998
@@ -2,8 +2,6 @@
      *  VGA characters/attributes
      */
 
-#include <linux/config.h>
-
 #ifdef MODULE
 #if defined(CONFIG_FBCON_VGA) || defined(CONFIG_FBCON_VGA_MODULE)
 #define FBCON_HAS_VGA
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c
--- v2.1.111/linux/drivers/video/fbcon.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon.c	Sun Jul 26 14:40:19 1998
@@ -25,7 +25,8 @@
  *			   Andreas Schwab
  *
  *  Hardware cursor support added by Emmanuel Marty (core@ggi-project.org)
- *  Smart redraw scrolling, arbitrary font width support added by 
+ *  Smart redraw scrolling, arbitrary font width support, 512char font support
+ *  added by 
  *                         Jakub Jelinek (jj@ultra.linux.cz)
  *
  *
@@ -108,7 +109,8 @@
 #define LOGO_LINE	(LOGO_W/8)
 
 struct display fb_display[MAX_NR_CONSOLES];
-
+static int logo_lines;
+static int logo_shown = -1;
 
 /*
  * Emmanuel: fbcon will now use a hardware cursor if the
@@ -396,11 +398,9 @@
     int nr_rows, nr_cols;
     int old_rows, old_cols;
     unsigned short *save = NULL, *r, *q;
-    int logo_lines = 0;
     /* Only if not module */
     extern int initmem_freed;
     struct fbcon_font_desc *font;
-    
     if (con != fg_console || initmem_freed || p->type == FB_TYPE_TEXT)
     	logo = 0;
 
@@ -485,6 +485,10 @@
     }
     p->vrows = p->var.yres_virtual/p->fontheight;
     conp->vc_can_do_color = p->var.bits_per_pixel != 1;
+    p->fgshift = 8;
+    p->bgshift = 12;
+    p->charmask = 0xff;
+    conp->vc_hi_font_mask = 0;
 
     if (!p->dispsw) {
 	printk(KERN_WARNING "fbcon_setup: type %d (aux %d, depth %d) not "
@@ -512,8 +516,11 @@
 	    update_screen(con); /* So that we set origin correctly */
     }
 	
-    if (logo)
+    if (logo) {
+    	logo_shown = fg_console;
     	fbcon_show_logo(); /* This is protected above by initmem_freed */
+    	conp->vc_top = logo_lines;
+    }
 }
 
 
@@ -1025,7 +1032,7 @@
 {
     int unit = conp->vc_num;
     struct display *p = &fb_display[unit];
-
+    
     if (!p->can_soft_blank && console_blanked)
 	return;
 
@@ -1033,9 +1040,9 @@
 	return;
 
     if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
-	 (sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
-	((dy <= p->cursor_y) && (p->cursor_y < dy+height) &&
-	 (dx <= p->cursor_x) && (p->cursor_x < dx+width)))
+	  (sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
+	 ((dy <= p->cursor_y) && (p->cursor_y < dy+height) &&
+	  (dx <= p->cursor_x) && (p->cursor_x < dx+width)))
 	fbcon_cursor(conp, CM_ERASE);
 
     /*  Split blits that cross physical y_wrap case.
@@ -1048,7 +1055,6 @@
     fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll);
 }
 
-
 static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx,
 			    int height, int width, u_int y_break)
 {
@@ -1087,6 +1093,13 @@
     struct display *p = &fb_display[unit];
     struct fb_info *info = p->fb_info;
 
+    if (logo_shown >= 0) {
+    	struct vc_data *conp2 = vc_cons[logo_shown].d;
+    	
+    	if (conp2->vc_top == logo_lines && conp2->vc_bottom == conp2->vc_rows)
+    		conp2->vc_top = 0;
+    	logo_shown = -1;
+    }
     p->var.yoffset = p->yscroll*p->fontheight;
     switch (p->scrollmode) {
 	case SCROLL_YWRAP:
@@ -1153,23 +1166,62 @@
 static inline int fbcon_get_font(int unit, struct console_font_op *op)
 {
     struct display *p = &fb_display[unit];
-    char *data = op->data;
+    u8 *data = op->data;
     int i, j;
 
-    if (p->fontwidth != 8)		/* FIXME: Implement for wide fonts */
-        return -EINVAL;
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+    if (p->fontwidth != 8) return -EINVAL;
+#endif
     op->width = p->fontwidth;
     op->height = p->fontheight;
-    op->charcount = 256;
-    for (i = 0; i < 256; i++)
-	for (j = 0; j < p->fontheight; j++)
-	    data[i*32+j] = p->fontdata[i*p->fontheight+j];
+    op->charcount = (p->charmask == 0x1ff) ? 512 : 256;
+    if (!op->data) return 0;
+    
+    if (op->width <= 8) {
+    	for (i = 0; i < op->charcount; i++) {
+	    for (j = 0; j < p->fontheight; j++)
+		*data++ = p->fontdata[i*p->fontheight+j];
+	    data += 32 - p->fontheight;
+	}
+    }
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+    else if (op->width <= 16) {
+	for (i = 0; i < op->charcount; i++) {
+	    for (j = 0; j < p->fontheight; j++) {
+		*data++ = ((u16 *)p->fontdata)[i*p->fontheight+j] >> 8;
+		*data++ = ((u16 *)p->fontdata)[i*p->fontheight+j];
+	    }
+	    data += 2 * (32 - p->fontheight);
+	}
+    } else if (op->width <= 24) {
+	for (i = 0; i < op->charcount; i++) {
+	    for (j = 0; j < p->fontheight; j++) {
+		*data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 24;
+		*data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 16;
+		*data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 8;
+	    }
+	    data += 3 * (32 - p->fontheight);
+	}
+    } else {
+	for (i = 0; i < op->charcount; i++) {
+	    for (j = 0; j < p->fontheight; j++) {
+		*data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 24;
+		*data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 16;
+		*data++ = ((u32 *)p->fontdata)[i*p->fontheight+j] >> 8;
+		*data++ = ((u32 *)p->fontdata)[i*p->fontheight+j];
+	    }
+	    data += 4 * (32 - p->fontheight);
+	}
+    }
+#endif
     return 0;
 }
 
 
 #define REFCOUNT(fd)	(((int *)(fd))[-1])
 #define FNTSIZE(fd)	(((int *)(fd))[-2])
+#define FNTCHARCNT(fd)	(((int *)(fd))[-3])
+#define FNTSUM(fd)	(((int *)(fd))[-4])
 
 static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int userfont)
 {
@@ -1177,6 +1229,7 @@
     int resize;
     int w = op->width;
     int h = op->height;
+    int cnt;
     char *old_data = NULL;
 
     if (!fontwidthvalid(p,w)) {
@@ -1188,11 +1241,28 @@
     resize = (w != p->fontwidth) || (h != p->fontheight);
     if (p->userfont)
         old_data = p->fontdata;
+    if (userfont)
+        cnt = FNTCHARCNT(data);
+    else
+    	cnt = 256;
     p->fontdata = data;
     if ((p->userfont = userfont))
         REFCOUNT(data)++;
     p->fontwidth = w;
     p->fontheight = h;
+    if (p->conp->vc_hi_font_mask && cnt == 256) {
+    	p->conp->vc_hi_font_mask = 0;
+    	p->conp->vc_complement_mask >>= 1;
+    	p->fgshift--;
+    	p->bgshift--;
+    	p->charmask = 0xff;
+    } else if (!p->conp->vc_hi_font_mask && cnt == 512) {
+    	p->conp->vc_hi_font_mask = 0x100;
+    	p->conp->vc_complement_mask <<= 1;
+    	p->fgshift++;
+    	p->bgshift++;
+    	p->charmask = 0x1ff;
+    }
     fbcon_font_widths(p);
 
     if (resize) {
@@ -1210,7 +1280,7 @@
 	update_screen( unit );
 
     if (old_data && (--REFCOUNT(old_data) == 0))
-	kfree( old_data - 2*sizeof(int) );
+	kfree( old_data - 4*sizeof(int) );
 
     return 0;
 }
@@ -1227,6 +1297,8 @@
     od = &fb_display[h];
     if (od->fontdata == p->fontdata)
         return 0; /* already the same font... */
+    op->width = od->fontwidth;
+    op->height = od->fontheight;
     return fbcon_do_set_font(unit, op, od->fontdata, od->userfont);
 }
 
@@ -1234,21 +1306,94 @@
 {
     int w = op->width;
     int h = op->height;
-    int size = (w+7)/8 * h * 256;
-    int i, j;
-    u8 *new_data, *data = op->data;
+    int size = h;
+    int i, j, k;
+    u8 *new_data, *data = op->data, c, *p;
+    u32 d;
 
-    if (w != 8 || op->charcount != 256)
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+    if (w != 8)
+    	return -EINVAL;
+#endif
+
+    if (w > 32 || (op->charcount != 256 && op->charcount != 512))
         return -EINVAL;
+    
+    if (w > 8) { 
+    	if (w <= 16)
+    		size *= 2;
+    	else
+    		size *= 4;
+    }
+    size *= op->charcount;
        
-    if (!(new_data = kmalloc( 2*sizeof(int)+size, GFP_USER )))
+    if (!(new_data = kmalloc( 4*sizeof(int)+size, GFP_USER )))
         return -ENOMEM;
-    new_data += 2*sizeof(int);
+    new_data += 4*sizeof(int);
     FNTSIZE(new_data) = size;
+    FNTCHARCNT(new_data) = op->charcount;
     REFCOUNT(new_data) = 0; /* usage counter */
-    for (i = 0; i < 256; i++)
-	for (j = 0; j < h; j++)
-	    new_data[i*h+j] = data[i*32+j];
+    k = 0;
+    p = data;
+    if (w <= 8) {
+	for (i = 0; i < op->charcount; i++) {
+	    for (j = 0; j < h; j++) {
+	        c = *p++;
+		k += c;
+		new_data[i*h+j] = c;
+	    }
+	    p += 32 - h;
+	}
+    }
+#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY
+    else if (w <= 16) {
+	for (i = 0; i < op->charcount; i++) {
+	    for (j = 0; j < h; j++) {
+	        d = (p[0] << 8) | p[1];
+	        p += 2;
+		k += d;
+		((u16 *)new_data)[i*h+j] = d;
+	    }
+	    p += 2*(32 - h);
+	}
+    } else {
+	for (i = 0; i < op->charcount; i++) {
+	    for (j = 0; j < h; j++) {
+	    	if (w <= 24) {
+		    d = (p[0] << 24) | 
+			(p[1] << 16) | 
+			(p[2] << 8);
+		    p += 3;
+		} else {
+		    d = (p[0] << 24) | 
+			(p[1] << 16) | 
+			(p[2] << 8) |
+			p[3];
+		    p += 4;
+		}
+		k += d;
+		((u32 *)new_data)[i*h+j] = d;
+	    }
+	    if (w <= 24)
+	    	p += 3*(32 - h);
+	    else
+	        p += 4*(32 - h);
+	}
+    }
+#endif
+    FNTSUM(new_data) = k;
+    /* Check if the same font is on some other console already */
+    for (i = 0; i < MAX_NR_CONSOLES; i++) {
+    	if (fb_display[i].userfont &&
+    	    fb_display[i].fontdata &&
+    	    FNTSUM(fb_display[i].fontdata) == k &&
+    	    FNTSIZE(fb_display[i].fontdata) == size &&
+	    !memcmp(fb_display[i].fontdata, new_data, size)) {
+	    kfree(new_data - 4*sizeof(int));
+	    new_data = fb_display[i].fontdata;
+	    break;
+    	}
+    }
     return fbcon_do_set_font(unit, op, new_data, 1);
 }
 
@@ -1269,7 +1414,6 @@
     }
     op->width = f->width;
     op->height = f->height;
-    op->charcount = 256;
     return fbcon_do_set_font(unit, op, f->data, 0);
 }
 
@@ -1371,7 +1515,6 @@
 	fbcon_cursor(conp, CM_DRAW);
     return 0;
 }
-
 
 __initfunc(static int fbcon_show_logo( void ))
 {
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbcon.h linux/drivers/video/fbcon.h
--- v2.1.111/linux/drivers/video/fbcon.h	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fbcon.h	Sun Jul 26 14:40:19 1998
@@ -11,6 +11,7 @@
 #ifndef __VIDEO_FBCON_H
 #define __VIDEO_FBCON_H
 
+#include <linux/config.h>
 #include <linux/console_struct.h>
 
 
@@ -35,11 +36,21 @@
     unsigned int fontwidthmask;      /* 1 at (1 << (width - 1)) if width is supported */
 }; 
 
+#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY
+
+/* fontwidth w is supported by dispsw */
+#define FONTWIDTH(w)	(1 << ((8) - 1))
+/* fontwidths w1-w2 inclusive are supported by dispsw */
+#define FONTWIDTHRANGE(w1,w2)	FONTWIDTH(8)
+
+#else
+
 /* fontwidth w is supported by dispsw */
 #define FONTWIDTH(w)	(1 << ((w) - 1))
 /* fontwidths w1-w2 inclusive are supported by dispsw */
 #define FONTWIDTHRANGE(w1,w2)	(FONTWIDTH(w2+1) - FONTWIDTH(w1))
 
+#endif
 
     /*
      *  Attribute Decoding
@@ -47,11 +58,11 @@
 
 /* Color */
 #define attr_fgcol(p,s)    \
-	(((s) >> ((p)->inverse ? 12 : 8)) & 0x0f)
+	(((s) >> ((p)->fgshift)) & 0x0f)
 #define attr_bgcol(p,s)    \
-	(((s) >> ((p)->inverse ? 8 : 12)) & 0x0f)
+	(((s) >> ((p)->bgshift)) & 0x0f)
 #define	attr_bgcol_ec(p,conp) \
-	(((conp)->vc_video_erase_char >> ((p)->inverse ? 8 : 12)) & 0x0f)
+	(((conp)->vc_video_erase_char >> ((p)->bgshift)) & 0x0f)
 
 /* Monochrome */
 #define attr_bold(p,s) \
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fbgen.c linux/drivers/video/fbgen.c
--- v2.1.111/linux/drivers/video/fbgen.c	Thu Mar 26 15:57:04 1998
+++ linux/drivers/video/fbgen.c	Sun Jul 26 14:40:19 1998
@@ -17,45 +17,8 @@
 #include <asm/uaccess.h>
 
 
-
 static int currcon = 0;
 
-static struct display disp;
-
-
-    /*
-     *  `Generic' versions of the frame buffer device operations
-     */
-
-extern int fbgen_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info);
-extern int fbgen_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-extern int fbgen_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-extern int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info);
-extern int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info);
-extern int fbgen_pan_display(struct fb_var_screeninfo *var, int con,
-			     struct fb_info *info);
-extern int fbgen_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg, int con,
-		       struct fb_info *info);
-
-
-    /*
-     *  Helper functions
-     */
-
-int fbgen_do_set_var(struct fb_var_screeninfo *var, int isactive,
-		     struct fb_info_gen *info);
-void fbgen_set_disp(int con, struct fb_info_gen *info);
-void fbgen_install_cmap(int con, struct fb_info_gen *info);
-int fbgen_update_var(int con, struct fb_info *info);
-int fbgen_switch(int con, struct fb_info *info);
-void fbgen_blank(int blank, struct fb_info *info);
-
 
 /* ---- `Generic' versions of the frame buffer device operations ----------- */
 
@@ -156,9 +119,10 @@
     else
 	if (fb_display[con].cmap.len)	/* non default colormap ? */
 	    fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-	else
-	    fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
-			 cmap, kspc ? 0 : 2);
+	else {
+	    int size = fb_display[con].var.bits_per_pixel == 16 ? 64 : 256;
+	    fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+	}
     return 0;
 }
 
@@ -175,8 +139,8 @@
     int err;
 
     if (!fb_display[con].cmap.len) {	/* no colormap allocated ? */
-	if ((err = fb_alloc_cmap(&fb_display[con].cmap,
-				 1 << fb_display[con].var.bits_per_pixel, 0)))
+	int size = fb_display[con].var.bits_per_pixel == 16 ? 64 : 256;
+	if ((err = fb_alloc_cmap(&fb_display[con].cmap, size, 0)))
 	    return err;
     }
     if (con == currcon)			/* current console ? */
@@ -272,7 +236,7 @@
     if (con >= 0)
 	display = &fb_display[con];
     else
-	display = &disp;	/* used during initialization */
+	display = info->info.disp;	/* used during initialization */
 
     if (con == -1)
 	fbhw->get_par(&par, info);
@@ -314,9 +278,11 @@
     if (fb_display[con].cmap.len)
 	fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1,
 		    fbhw->setcolreg, &info->info);
-    else
-	fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
-		    &fb_display[con].var, 1, fbhw->setcolreg, &info->info);
+    else {
+	int size = fb_display[con].var.bits_per_pixel == 16 ? 64 : 256;
+	fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1,
+		    fbhw->setcolreg, &info->info);
+    }
 }
 
 
diff -u --recursive --new-file v2.1.111/linux/drivers/video/font_acorn_8x8.c linux/drivers/video/font_acorn_8x8.c
--- v2.1.111/linux/drivers/video/font_acorn_8x8.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/font_acorn_8x8.c	Sun Jul 26 14:40:19 1998
@@ -1,6 +1,5 @@
 /* Acorn-like font definition, with PC graphics characters */
 
-#include <linux/config.h>
 #include "font.h"
 
 static unsigned char acorndata_8x8[] = {
diff -u --recursive --new-file v2.1.111/linux/drivers/video/fonts.c linux/drivers/video/fonts.c
--- v2.1.111/linux/drivers/video/fonts.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/fonts.c	Sun Jul 26 14:40:19 1998
@@ -30,7 +30,7 @@
     &font_vga_8x16,
 #endif
 #ifdef CONFIG_FONT_6x11
-#if !defined(CONFIG_MAC) && !defined(CONFIG_FB_SBUS)
+#if defined(CONFIG_MAC) || defined(CONFIG_FB_SBUS)
 #undef NO_FONTS
 #endif
     &font_vga_6x11,
@@ -40,7 +40,7 @@
     &font_sun_8x16,
 #endif
 #ifdef CONFIG_FONT_SUN12x22
-#if !defined(CONFIG_FB_SBUS) && !defined(CONFIG_FBCON_CFB8)
+#if defined(CONFIG_FB_SBUS) || defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB24) || defined(CONFIG_FBCON_CFB32)
 #undef NO_FONTS
 #endif
     &font_sun_12x22,
diff -u --recursive --new-file v2.1.111/linux/drivers/video/macfb.c linux/drivers/video/macfb.c
--- v2.1.111/linux/drivers/video/macfb.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/macfb.c	Sun Jul 26 14:40:19 1998
@@ -2,6 +2,7 @@
  *	We've been given MAC frame buffer info by the booter. Now go set it up
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -42,7 +43,7 @@
 	{0,0,0},	/* transparency */
 	0,		/* standard pixel format */
 	FB_ACTIVATE_NOW,
-	274,195,	/* 14" monitor - the late Mikael Nykvist's anyway */
+	274,195,	/* 14" monitor *Mikael Nykvist's anyway* */
 	0,		/* The only way to accelerate a mac is .. */
 	0L,0L,0L,0L,0L,
 	0L,0L,0,	/* No sync info */
diff -u --recursive --new-file v2.1.111/linux/drivers/video/macmodes.c linux/drivers/video/macmodes.c
--- v2.1.111/linux/drivers/video/macmodes.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/macmodes.c	Sun Jul 26 14:40:19 1998
@@ -9,6 +9,7 @@
  */
 
 
+#include <linux/config.h>
 #include <linux/tty.h>
 #include <linux/fb.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.1.111/linux/drivers/video/macmodes.h linux/drivers/video/macmodes.h
--- v2.1.111/linux/drivers/video/macmodes.h	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/macmodes.h	Sun Jul 26 14:40:19 1998
@@ -50,3 +50,11 @@
 extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
 			    int *cmode);
 extern int mac_map_monitor_sense(int sense);
+
+
+    /*
+     *  Addresses in NVRAM where video mode and pixel size are stored.
+     */
+
+#define NV_VMODE		0x140f
+#define NV_CMODE		0x1410
diff -u --recursive --new-file v2.1.111/linux/drivers/video/offb.c linux/drivers/video/offb.c
--- v2.1.111/linux/drivers/video/offb.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/offb.c	Sun Jul 26 14:40:19 1998
@@ -282,6 +282,13 @@
 #ifdef CONFIG_FB_CT65550
 extern void chips_of_init(struct device_node *dp);
 #endif /* CONFIG_FB_CT65550 */
+#ifdef CONFIG_FB_CONTROL
+extern void control_of_init(struct device_node *dp);
+#endif /* CONFIG_FB_CONTROL */
+#ifdef CONFIG_FB_PLATINUM
+extern void platinum_of_init(struct device_node *dp);
+#endif /* CONFIG_FB_PLATINUM */
+
 
     /*
      *  Initialisation
@@ -318,6 +325,19 @@
 		continue;
 	    }
 #endif /* CONFIG_FB_CT65550 */
+#ifdef CONFIG_FB_CONTROL
+		if(!strcmp(dp->name, "control")) {
+			control_of_init(dp);
+			continue;
+		}
+#endif /* CONFIG_FB_CONTROL */
+#ifdef CONFIG_FB_PLATINUM
+	    if (!strncmp(dp->name, "platinum",8)) {
+	    	printk("jonh: offb_init sees device node %s\n", dp->name);
+		platinum_of_init(dp);
+		continue;
+	    }
+#endif /* CONFIG_FB_PLATINUM */
 	}
 
 	info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC);
diff -u --recursive --new-file v2.1.111/linux/drivers/video/platinumfb.c linux/drivers/video/platinumfb.c
--- v2.1.111/linux/drivers/video/platinumfb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/platinumfb.c	Sun Jul 26 14:40:19 1998
@@ -0,0 +1,1052 @@
+/*
+ *  platinumfb.c -- frame buffer device for the PowerMac 'platinum' display
+ *
+ *  Created 12 July 1998 by Dan Jacobowitz <dan@debian.org>
+ *  Copyright (C) 1998 Dan Jacobowitz
+ *
+ *  Frame buffer structure from:
+ *    drivers/video/chipsfb.c -- frame buffer device for
+ *    Chips & Technologies 65550 chip.
+ *
+ *    Copyright (C) 1998 Paul Mackerras
+ *
+ *    This file is derived from the Powermac "chips" driver:
+ *    Copyright (C) 1997 Fabio Riccardi.
+ *    And from the frame buffer device for Open Firmware-initialized devices:
+ *    Copyright (C) 1997 Geert Uytterhoeven.
+ *
+ *  Hardware information from:
+ *    platinum.c: Console support for PowerMac "platinum" display adaptor.
+ *    Copyright (C) 1996 Paul Mackerras
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/selection.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/nvram.h>
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#include <asm/vc_ioctl.h>
+#endif
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/adb.h>
+#include <asm/cuda.h>
+
+#include "fbcon.h"
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb16.h"
+#include "fbcon-cfb32.h"
+
+#include "macmodes.h"
+#include "platinumfb.h"
+
+static int currcon = 0;
+static int switching = 0;
+
+struct fb_par_platinum {
+	int	vmode, cmode;
+	int	xres, yres;
+	int	vxres, vyres;
+	int	xoffset, yoffset;
+};
+
+struct fb_info_platinum {
+	struct fb_info			info;
+	struct fb_fix_screeninfo	fix;
+	struct fb_var_screeninfo	var;
+	struct display			disp;
+	struct fb_par_platinum		par;
+	struct {
+		__u8 red, green, blue;
+	}			palette[256];
+	
+	volatile struct cmap_regs	*cmap_regs;
+	unsigned long		cmap_regs_phys;
+	
+	volatile struct platinum_regs	*platinum_regs;
+	unsigned long		platinum_regs_phys;
+	
+	__u8			*frame_buffer;
+	__u8			*base_frame_buffer;
+	unsigned long		frame_buffer_phys;
+	
+	int			sense;
+	unsigned long		total_vram;
+};
+
+/*
+ * Exported functions
+ */
+void platinum_init(void);
+void platinum_of_init(struct device_node *dp);
+
+static int platinum_open(struct fb_info *info, int user);
+static int platinum_release(struct fb_info *info, int user);
+static int platinum_get_fix(struct fb_fix_screeninfo *fix, int con,
+			 struct fb_info *info);
+static int platinum_get_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info);
+static int platinum_set_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info);
+static int platinum_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *info);
+static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info);
+static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info);
+static int platinum_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg, int con, struct fb_info *info);
+
+static int read_platinum_sense(struct fb_info_platinum *p);
+static inline int platinum_vram_reqd(int video_mode, int color_mode);
+static void set_platinum_clock(struct fb_info_platinum *p, unsigned char *params);
+static void platinum_set_hardware(struct fb_info_platinum *p);
+static void platinum_par_to_all(struct fb_info_platinum *p, int init);
+static inline void platinum_par_to_var(struct fb_par_platinum *par, struct fb_var_screeninfo *var);
+static int platinum_var_to_par(struct fb_var_screeninfo *var,
+	struct fb_par_platinum *par, const struct fb_info *fb_info);
+
+static void platinum_init_info(struct fb_info *info, struct fb_info_platinum *p);
+static void platinum_par_to_display(struct fb_par_platinum *par,
+  struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_platinum *p);
+static void platinum_init_display(struct display *disp);
+static void platinum_par_to_fix(struct fb_par_platinum *par, struct fb_fix_screeninfo *fix,
+	struct fb_info_platinum *p);
+static void platinum_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_platinum *p);
+
+static struct fb_ops platinumfb_ops = {
+	platinum_open,
+	platinum_release,
+	platinum_get_fix,
+	platinum_get_var,
+	platinum_set_var,
+	platinum_get_cmap,
+	platinum_set_cmap,
+	platinum_pan_display,
+	platinum_ioctl
+};
+
+static int platinum_getcolreg(u_int regno, u_int *red, u_int *green,
+			     u_int *blue, u_int *transp, struct fb_info *info);
+static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			     u_int transp, struct fb_info *info);
+static void do_install_cmap(int con, struct fb_info *info);
+
+#define FUNCID { printk(KERN_INFO "entering %s\n", __FUNCTION__); }
+
+__openfirmware
+
+
+static int platinum_open(struct fb_info *info, int user)
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int platinum_release(struct fb_info *info, int user)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int platinum_get_fix(struct fb_fix_screeninfo *fix, int con,
+			 struct fb_info *info)
+{
+	struct fb_info_platinum *cp = (struct fb_info_platinum *) info;
+
+	*fix = cp->fix;
+	return 0;
+}
+
+static int platinum_get_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info)
+{
+	struct fb_info_platinum *cp = (struct fb_info_platinum *) info;
+
+	*var = cp->var;
+	return 0;
+}
+
+/* Sets everything according to var */
+static int platinum_set_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info)
+{
+	struct fb_info_platinum *p = (struct fb_info_platinum *) info;
+	struct display *disp;
+	struct fb_par_platinum par;
+	int depthchange, err;
+
+//    FUNCID;
+	disp = (con >= 0) ? &fb_display[con] : &p->disp;
+	if((err = platinum_var_to_par(var, &par, info))) {
+		printk (KERN_ERR "Error in platinum_set_var, calling platinum_var_to_par: %d.\n", err);
+		return err;
+	}
+	
+	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) {
+		printk("Not activating, in platinum_set_var.\n");
+		platinum_par_to_var(&par, var);
+		return 0;
+	}
+/* I know, we want to use fb_display[con], but grab certain info from p->var instead. */
+#define DIRTY(x) (p->var.x != var->x)
+	depthchange = DIRTY(bits_per_pixel);
+	if(!DIRTY(xres) && !DIRTY(yres) && !DIRTY(xres_virtual) &&
+	   !DIRTY(yres_virtual) && !DIRTY(bits_per_pixel)) {
+	   	platinum_par_to_var(&par, var);
+		p->var = disp->var = *var;
+		return 0;
+	}
+	printk("Original bpp is %d, new bpp %d.\n", p->var.bits_per_pixel, var->bits_per_pixel);
+	/* OK, we're getting here at the right times... */
+	p->par = par;
+	platinum_par_to_var(&par, var);
+	p->var = *var;
+	platinum_par_to_fix(&par, &p->fix, p);
+	platinum_par_to_display(&par, disp, &p->fix, p);
+	p->disp = *disp;
+	
+	if(info->changevar && !switching)	/* Don't want to do this if just switching consoles. */
+		(*info->changevar)(con);
+	if(con == currcon)
+		platinum_set_hardware(p);
+	if(depthchange)
+		if((err = fb_alloc_cmap(&disp->cmap, 0, 0)))
+			return err;
+	if(depthchange || switching)
+		do_install_cmap(con, info);
+	return 0;
+}
+
+static int platinum_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *info)
+{
+    /*
+     *  Pan (or wrap, depending on the `vmode' field) the display using the
+     *  `xoffset' and `yoffset' fields of the `var' structure.
+     *  If the values don't fit, return -EINVAL.
+     */
+
+//	FUNCID;
+	if (var->xoffset != 0 || var->yoffset != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info)
+{
+//    FUNCID;
+	if (con == currcon)		/* current console? */
+		return fb_get_cmap(cmap, &fb_display[con].var, kspc,
+				   platinum_getcolreg, info);
+	if (fb_display[con].cmap.len)	/* non default colormap? */
+		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc? 0: 2);
+	else {
+		int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+		fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+	}
+	return 0;
+}
+
+static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			 struct fb_info *info)
+{
+	struct display *disp = &fb_display[con];
+	int err;
+
+//    FUNCID;
+	if (disp->cmap.len == 0) {
+		int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+		err = fb_alloc_cmap(&disp->cmap, size, 0);
+		if (err)
+			return err;
+	}
+
+	if (con == currcon)
+		return fb_set_cmap(cmap, &disp->var, kspc, platinum_setcolreg,
+				   info);
+	fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
+	return 0;
+}
+
+static int platinum_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg, int con, struct fb_info *info)
+{
+//	FUNCID;
+	return -EINVAL;
+}
+
+static int platinum_switch(int con, struct fb_info *info)
+{
+//    FUNCID;
+	if (fb_display[currcon].cmap.len)
+		fb_get_cmap(&fb_display[currcon].cmap,
+			    &fb_display[currcon].var, 1, platinum_getcolreg,
+			    info);
+	currcon = con;
+#if 0
+	platinum_var_to_par(&fb_display[currcon].var, &par, info);
+	platinum_set_par(&par, info); /*STOPPEDHERE - did i define that? */
+	do_install_cmap(con, info);
+#else
+	/* I see no reason not to do this.  Minus info->changevar(). */
+	/* DOH.  This makes platinum_set_var compare, you guessed it, */
+	/* fb_display[con].var (first param), and fb_display[con].var! */
+	/* Perhaps I just fixed that... */
+	switching = 1;
+	platinum_set_var(&fb_display[con].var, con, info);
+	switching = 0;
+#endif
+	return 0;
+}
+
+static int platinum_updatevar(int con, struct fb_info *info)
+{
+	return 0;
+}
+
+static void platinum_blank(int blank_mode, struct fb_info *info)
+{
+/*
+ *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
+ *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
+ *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
+ *  to e.g. a video mode which doesn't support it. Implements VESA suspend
+ *  and powerdown modes on hardware that supports disabling hsync/vsync:
+ *    blank_mode == 2: suspend vsync
+ *    blank_mode == 3: suspend hsync
+ *    blank_mode == 4: powerdown
+ */
+/* [danj] I think there's something fishy about those constants... */
+/*
+	struct fb_info_platinum *p = (struct fb_info_platinum *) info;
+	int	ctrl;
+
+	ctrl = ld_le32(&p->platinum_regs->ctrl.r) | 0x33;
+	if (blank_mode)
+		--blank_mode;
+	if (blank_mode & VESA_VSYNC_SUSPEND)
+		ctrl &= ~3;
+	if (blank_mode & VESA_HSYNC_SUSPEND)
+		ctrl &= ~0x30;
+	out_le32(&p->platinum_regs->ctrl.r, ctrl);
+*/
+/* TODO: Figure out how the heck to powerdown this thing! */
+//FUNCID;
+    return;
+}
+
+static int platinum_getcolreg(u_int regno, u_int *red, u_int *green,
+			     u_int *blue, u_int *transp, struct fb_info *info)
+{
+	struct fb_info_platinum *p = (struct fb_info_platinum *) info;
+
+//    FUNCID;
+	if (regno > 255 || regno < 0)
+		return 1;
+	*red = p->palette[regno].red;
+	*green = p->palette[regno].green;
+	*blue = p->palette[regno].blue;
+	return 0;
+}
+
+static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			     u_int transp, struct fb_info *info)
+{
+	struct fb_info_platinum *p = (struct fb_info_platinum *) info;
+
+//    FUNCID;
+	if (regno > 255 || regno < 0)
+		return 1;
+	p->palette[regno].red = red;
+	p->palette[regno].green = green;
+	p->palette[regno].blue = blue;
+
+	out_8(&p->cmap_regs->addr, regno);	/* tell clut what addr to fill	*/
+	out_8(&p->cmap_regs->lut, red);		/* send one color channel at	*/
+	out_8(&p->cmap_regs->lut, green);	/* a time...			*/
+	out_8(&p->cmap_regs->lut, blue);
+
+	if(regno < 16) {
+#if 0
+#ifdef FBCON_HAS_CFB16
+		fbcon_cfb16_cmap[regno] = (red << 10) | (green << 5) | blue;
+#endif
+#ifdef FBCON_HAS_CFB32
+		fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue;
+		/* I think. */
+#endif
+#else
+#ifdef FBCON_HAS_CFB16
+		fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno;
+#endif
+#ifdef FBCON_HAS_CFB32
+		fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) | (regno << 8) | regno;
+		/* I think. */
+#endif
+#endif
+	}
+	return 0;
+}
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+//    FUNCID;
+	if (con != currcon)
+		return;
+	if (fb_display[con].cmap.len)
+		fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1,
+			    platinum_setcolreg, info);
+	else {
+		int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+		fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1,
+			    platinum_setcolreg, info);
+	}
+}
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+extern struct vc_mode display_info;
+extern struct fb_info *console_fb_info;
+#if 0
+extern int (*console_setmode_ptr)(struct vc_mode *, int);
+extern int (*console_set_cmap_ptr)(struct fb_cmap *, int, int,
+				   struct fb_info *);
+int console_setmode(struct vc_mode *, int);
+#endif
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+
+static inline int platinum_vram_reqd(int video_mode, int color_mode)
+{
+	return vmode_attrs[video_mode - 1].vres
+		* platinum_reg_init[video_mode-1]->pitch[color_mode];
+}
+
+#define STORE_D2(a, d) { \
+	out_8(&p->cmap_regs->addr, (a+32)); \
+	out_8(&p->cmap_regs->d2, (d)); \
+}
+
+static void set_platinum_clock(struct fb_info_platinum *p, unsigned char *clock_params)
+{
+//    FUNCID;
+	STORE_D2(6, 0xc6);
+	out_8(&p->cmap_regs->addr,3+32);
+	if (in_8(&p->cmap_regs->d2) == 2) {
+		STORE_D2(7, clock_params[0]);
+		STORE_D2(8, clock_params[1]);
+		STORE_D2(3, 3);
+	} else {
+		STORE_D2(4, clock_params[0]);
+		STORE_D2(5, clock_params[1]);
+		STORE_D2(3, 2);
+	}
+
+	__delay(5000);
+	STORE_D2(9, 0xa6);
+}
+
+
+__initfunc(static void init_platinum(struct fb_info_platinum *p))
+{
+	struct fb_par_platinum *par = &p->par;
+
+//    FUNCID;
+	p->sense = read_platinum_sense(p);
+	printk("Monitor sense value = 0x%x, ", p->sense);
+	/* Try to pick a video mode out of NVRAM if we have one. */
+	par->vmode = nvram_read_byte(NV_VMODE);
+	if(par->vmode <= 0 || par->vmode > VMODE_MAX || !platinum_reg_init[par->vmode - 1])
+		par->vmode = VMODE_CHOOSE;
+	if(par->vmode == VMODE_CHOOSE)
+		par->vmode = mac_map_monitor_sense(p->sense);
+	if(!platinum_reg_init[par->vmode - 1])
+		par->vmode = VMODE_640_480_67;
+
+	par->cmode = nvram_read_byte(NV_CMODE);
+	if(par->cmode < CMODE_8 || par->cmode > CMODE_32)
+		par->cmode = CMODE_8;
+	/*
+	 * Reduce the pixel size if we don't have enough VRAM.
+	 */
+	while(par->cmode > CMODE_8 && platinum_vram_reqd(par->vmode, par->cmode) > p->total_vram)
+		par->cmode--;
+	
+	printk("using video mode %d and color mode %d.\n", par->vmode, par->cmode);
+	
+	par->vxres = par->xres = vmode_attrs[par->vmode - 1].hres;
+	par->vyres = par->yres = vmode_attrs[par->vmode - 1].vres;
+	par->xoffset = par->yoffset = 0;
+	
+	platinum_par_to_all(p, 1);
+	
+	if (register_framebuffer(&p->info) < 0) {
+		kfree(p);
+		return;
+	}
+	platinum_set_hardware(p);
+	
+	printk("fb%d: platinum display adapter\n", GET_FB_IDX(p->info.node));	
+}
+
+/* Now how about actually saying, Make it so! */
+/* Some things in here probably don't need to be done each time. */
+static void platinum_set_hardware(struct fb_info_platinum *p)
+{
+	struct platinum_regvals	*init;
+	int			i, dtype, clkmode;
+	int			vmode, cmode;
+	
+//    FUNCID;
+	vmode = p->par.vmode;
+	cmode = p->par.cmode;
+
+	init = platinum_reg_init[vmode - 1];
+
+	/* Initialize display timing registers */
+	out_be32(&p->platinum_regs->reg[24].r, 7);	/* turn display off */
+
+	for (i = 0; i < 26; ++i)
+		out_be32(&p->platinum_regs->reg[i+32].r, init->regs[i]);
+	out_be32(&p->platinum_regs->reg[26+32].r, (p->total_vram == 0x100000 ?
+						   init->offset[cmode] + 4 - cmode :
+						   init->offset[cmode]));
+	out_be32(&p->platinum_regs->reg[16].r, (unsigned) p->frame_buffer_phys + init->fb_offset);
+	out_be32(&p->platinum_regs->reg[18].r, init->pitch[cmode]);
+	out_be32(&p->platinum_regs->reg[19].r, (p->total_vram == 0x100000 ?
+						init->mode[cmode+1] :
+						init->mode[cmode]));
+	out_be32(&p->platinum_regs->reg[20].r, (p->total_vram == 0x100000 ? 0x11 : 0x1011));
+	out_be32(&p->platinum_regs->reg[21].r, 0x100);
+	out_be32(&p->platinum_regs->reg[22].r, 1);
+	out_be32(&p->platinum_regs->reg[23].r, 1);
+	out_be32(&p->platinum_regs->reg[26].r, 0xc00);
+	out_be32(&p->platinum_regs->reg[27].r, 0x235);
+	/* out_be32(&p->platinum_regs->reg[27].r, 0x2aa); */
+
+	STORE_D2(0, (p->total_vram == 0x100000 ?
+		     init->dacula_ctrl[cmode] & 0xf :
+		     init->dacula_ctrl[cmode]));
+	STORE_D2(1, 4);
+	STORE_D2(2, 0);
+	/*
+	 * Try to determine whether we have an old or a new DACula.
+	 */
+	out_8(&p->cmap_regs->addr, 0x40);
+	dtype = in_8(&p->cmap_regs->d2);
+	switch (dtype) {
+	case 0x3c:
+		clkmode = 1;
+		break;
+	case 0x84:
+		clkmode = 0;
+		break;
+	default:
+		clkmode = 0;
+		printk("Unknown DACula type: %x\n", dtype);
+	}
+
+	set_platinum_clock(p, init->clock_params[clkmode]);
+
+	out_be32(&p->platinum_regs->reg[24].r, 0);	/* turn display on */
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+	/* And let the world know the truth. */
+	if (!console_fb_info || console_fb_info == &p->info) {
+		display_info.height = p->var.yres;
+		display_info.width = p->var.xres;
+		display_info.depth = ( (cmode == CMODE_32) ? 32 :
+				      ((cmode == CMODE_16) ? 16 : 8));
+		display_info.pitch = p->fix.line_length;
+		display_info.mode = vmode;
+		strncpy(display_info.name, "platinum",
+			sizeof(display_info.name));
+		display_info.fb_address = p->frame_buffer_phys
+					+ init->fb_offset
+					+ 0x10;
+		display_info.cmap_adr_address = p->cmap_regs_phys;
+		display_info.cmap_data_address = p->cmap_regs_phys + 0x30;
+		display_info.disp_reg_address = p->platinum_regs_phys;
+		console_fb_info = &p->info;
+	}
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+}
+
+__initfunc(void platinum_init(void))
+{
+#ifndef CONFIG_FB_OF
+	struct device_node *dp;
+
+	dp = find_devices("platinum");
+	if (dp != 0)
+		platinum_of_init(dp);
+#endif /* CONFIG_FB_OF */
+}
+
+__initfunc(void platinum_of_init(struct device_node *dp))
+{
+	struct fb_info_platinum	*p;
+	unsigned long		addr, size;
+	int			i, bank0, bank1, bank2, bank3;
+//FUNCID;	
+	if(dp->n_addrs != 2)
+		panic("expecting 2 address for platinum (got %d)", dp->n_addrs);
+	p = kmalloc(sizeof(*p), GFP_ATOMIC);
+	if (p == 0)
+		return;
+
+	/* Map in frame buffer and registers */
+	for (i = 0; i < dp->n_addrs; ++i) {
+		addr = dp->addrs[i].address;
+		size = dp->addrs[i].size;
+		if (size >= 0x400000) {
+			/* frame buffer - map only 4MB */
+			p->frame_buffer_phys = addr;
+			p->frame_buffer = __ioremap(addr, 0x400000, _PAGE_WRITETHRU);
+			p->base_frame_buffer = p->frame_buffer;
+		} else {
+			/* registers */
+			p->platinum_regs_phys = addr;
+			p->platinum_regs = ioremap(addr, size);
+		}
+	}
+	p->cmap_regs_phys = 0xf301b000;	/* XXX not in prom? */
+	p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000);
+
+	/* Grok total video ram */
+	out_be32(&p->platinum_regs->reg[16].r, (unsigned)p->frame_buffer_phys);
+	out_be32(&p->platinum_regs->reg[20].r, 0x1011);	/* select max vram */
+	out_be32(&p->platinum_regs->reg[24].r, 0);	/* switch in vram */
+	eieio();
+	p->frame_buffer[0x100000] = 0x34;
+	asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x100000]) : "memory");
+	p->frame_buffer[0x200000] = 0x56;
+	asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x200000]) : "memory");
+	p->frame_buffer[0x300000] = 0x78;
+	asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x300000]) : "memory");
+	bank0 = 1; /* builtin 1MB vram, always there */
+	bank1 = p->frame_buffer[0x100000] == 0x34;
+	bank2 = p->frame_buffer[0x200000] == 0x56;
+	bank3 = p->frame_buffer[0x300000] == 0x78;
+	p->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000;
+	printk("Total VRAM = %dMB\n", p->total_vram / 1024 / 1024);
+
+//	p->frame_buffer = p->base_frame_buffer
+//			+ platinum_reg_init[p->par.vmode-1]->fb_offset;
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#if 0
+	console_set_cmap_ptr = platinum_set_cmap;
+	console_setmode_ptr = platinum_console_setmode;
+#endif
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+
+	init_platinum(p);
+}
+
+/*
+ * Get the monitor sense value.
+ * Note that this can be called before calibrate_delay,
+ * so we can't use udelay.
+ */
+static int read_platinum_sense(struct fb_info_platinum *p)
+{
+	int sense;
+
+	out_be32(&p->platinum_regs->reg[23].r, 7);	/* turn off drivers */
+	__delay(2000);
+	sense = (~in_be32(&p->platinum_regs->reg[23].r) & 7) << 8;
+
+	/* drive each sense line low in turn and collect the other 2 */
+	out_be32(&p->platinum_regs->reg[23].r, 3);	/* drive A low */
+	__delay(2000);
+	sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 3) << 4;
+	out_be32(&p->platinum_regs->reg[23].r, 5);	/* drive B low */
+	__delay(2000);
+	sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 4) << 1;
+	sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 1) << 2;
+	out_be32(&p->platinum_regs->reg[23].r, 6);	/* drive C low */
+	__delay(2000);
+	sense |= (~in_be32(&p->platinum_regs->reg[23].r) & 6) >> 1;
+
+	out_be32(&p->platinum_regs->reg[23].r, 7);	/* turn off drivers */
+
+	return sense;
+}
+
+#if 0
+/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
+static int platinum_var_to_par(struct fb_var_screeninfo *var, 
+	struct fb_par_platinum *par, const struct fb_info *fb_info)
+{
+	int xres = var->xres;
+	int yres = var->yres;
+	int bpp = var->bits_per_pixel;
+	
+	struct platinum_regvals *init;
+	struct fb_info_platinum *p = (struct fb_info_platinum *) fb_info;
+
+//    FUNCID;
+    /*
+     *  Get the video params out of 'var'. If a value doesn't fit, round it up,
+     *  if it's too big, return -EINVAL.
+     *
+     *  Suggestion: Round up in the following order: bits_per_pixel, xres,
+     *  yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
+     *  bitfields, horizontal timing, vertical timing.
+     */
+	/* swiped by jonh from atyfb.c */
+	if (xres <= 512 && yres <= 384)
+		par->vmode = VMODE_512_384_60;		 /* 512x384, 60Hz */
+	else if (xres <= 640 && yres <= 480)
+		par->vmode = VMODE_640_480_67;		/* 640x480, 67Hz */
+	else if (xres <= 640 && yres <= 870)
+		par->vmode = VMODE_640_870_75P;		/* 640x870, 75Hz (portrait) */
+	else if (xres <= 768 && yres <= 576)
+		par->vmode = VMODE_768_576_50I;		/* 768x576, 50Hz (PAL full frame) */
+	else if (xres <= 800 && yres <= 600)
+		par->vmode = VMODE_800_600_75;		/* 800x600, 75Hz */
+	else if (xres <= 832 && yres <= 624)
+		par->vmode = VMODE_832_624_75;		/* 832x624, 75Hz */
+	else if (xres <= 1024 && yres <= 768)
+		par->vmode = VMODE_1024_768_75;		/* 1024x768, 75Hz */
+	else if (xres <= 1152 && yres <= 870)
+		par->vmode = VMODE_1152_870_75;		/* 1152x870, 75Hz */
+	else if (xres <= 1280 && yres <= 960)
+		par->vmode = VMODE_1280_960_75;		/* 1280x960, 75Hz */
+	else if (xres <= 1280 && yres <= 1024)
+		par->vmode = VMODE_1280_1024_75;	/* 1280x1024, 75Hz */
+	else {
+		printk(KERN_ERR "Bad  resolution in platinum_var_to_par()!\n");
+		return -EINVAL;
+	}
+	xres = vmode_attrs[par->vmode - 1].hres;
+	yres = vmode_attrs[par->vmode - 1].vres;
+
+/*
+	if (var->xres_virtual <= xres)
+		par->vxres = xres;
+	else
+		par->vxres = (var->xres_virtual+7) & ~7;
+	if (var->yres_virtual <= yres)
+		par->vyres = yres;
+	else
+		par->vyres = var->yres_virtual;
+
+	par->xoffset = (var->xoffset+7) & ~7;
+	par->yoffset = var->yoffset;
+	if (par->xoffset+xres > par->vxres || par->yoffset+yres > par->vyres)
+		return -EINVAL;
+*/
+
+	/* I'm too chicken to think about virtual	*/
+	/* resolutions just yet. Bok bok.			*/
+	
+	/* And I'm too chicken to even figure out what they are.  Awk awk. [danj] */
+	if (var->xres_virtual > xres || var->yres_virtual > yres
+		|| var->xoffset != 0 || var->yoffset != 0) {
+		printk(KERN_ERR "Bad  virtual resolution in platinum_var_to_par()!\n");
+		return -EINVAL;
+	}
+
+	par->xres = xres;
+	par->yres = yres;
+	par->vxres = xres;
+	par->vyres = yres;
+	par->xoffset = 0;
+	par->yoffset = 0;
+
+	if (bpp <= 8)
+		par->cmode = CMODE_8;
+	else if (bpp <= 16)
+		par->cmode = CMODE_16;
+	else if (bpp <= 32)
+		par->cmode = CMODE_32;
+	else {
+		printk(KERN_ERR "Bad color mode in platinum_var_to_par()!\n");
+		return -EINVAL;
+	}
+
+	if (platinum_vram_reqd(par->vmode, par->cmode) > p->total_vram) {
+		printk(KERN_ERR "Bad vram size requested in platinum_var_to_par()!\n");
+		return -EINVAL;
+	}
+	/* Check if we know about the wanted video mode */
+	init = platinum_reg_init[par->vmode-1];
+	if (init == NULL) {
+		/* I'm not sure if platinum has any specific requirements --	*/
+		/* if we have a regvals struct, we're good to go?		*/
+		printk(KERN_ERR "platinum_reg_init failed platinum_var_to_par()!\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+#else
+/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
+static int platinum_var_to_par(struct fb_var_screeninfo *var, 
+	struct fb_par_platinum *par, const struct fb_info *fb_info)
+{
+	struct fb_info_platinum *p = (struct fb_info_platinum *) fb_info;
+	
+//    FUNCID;
+	if(mac_var_to_vmode(var, &par->vmode, &par->cmode) != 0)
+		return -EINVAL;
+	par->xres = par->vxres = vmode_attrs[par->vmode - 1].hres;
+	par->yres = par->vyres = vmode_attrs[par->vmode - 1].vres;
+	par->xoffset = par->yoffset = 0;
+	
+	if (platinum_vram_reqd(par->vmode, par->cmode) > p->total_vram)
+		return -EINVAL;
+
+	/* Check if we know about the wanted video mode */
+	if(!platinum_reg_init[par->vmode-1]) {
+		/* I'm not sure if platinum has any specific requirements --	*/
+		/* if we have a regvals struct, we're good to go?		*/
+		return -EINVAL;
+	}
+	return 0;
+}
+#endif
+
+#if 0
+static void platinum_par_to_var(struct fb_par_platinum *par, struct fb_var_screeninfo *var)
+{
+	memset(var, 0, sizeof(*var));
+	var->xres = vmode_attrs[par->vmode - 1].hres;
+	var->yres = vmode_attrs[par->vmode - 1].vres;
+	var->xres_virtual = var->xres;
+	var->yres_virtual = var->yres;	/* For now. */
+	var->xoffset = par->xoffset;
+	var->yoffset = par->yoffset;
+	var->grayscale = 0;
+	
+	if(par->cmode != CMODE_8 && par->cmode != CMODE_16 && par->cmode != CMODE_32) {
+		printk(KERN_ERR "Bad color mode in platinum_par_to_var()!\n");
+		par->cmode = CMODE_8;
+	}
+	switch(par->cmode) {
+	case CMODE_8:
+		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;
+		break;
+	case CMODE_16:	/* RGB 555 */
+		var->bits_per_pixel = 16;
+		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 = 0;
+		var->transp.length = 0;
+		break;
+	case CMODE_32:	/* RGB 888 */
+		var->bits_per_pixel = 32;
+		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;
+		break;
+	}
+	var->red.msb_right = 0;
+	var->green.msb_right = 0;
+	var->blue.msb_right = 0;
+	var->transp.msb_right = 0;
+	var->nonstd = 0;
+	var->activate = 0;
+	var->height = -1;
+	var->width = -1;
+	var->vmode = FB_VMODE_NONINTERLACED;
+
+	/* these are total guesses, copied right out of atyfb.c */
+	var->left_margin = var->right_margin = 64;
+	var->upper_margin = var->lower_margin = 32;
+	var->hsync_len = 8;
+	var->vsync_len = 8;
+	var->sync = 0;
+
+#if 1
+/* jonh's pixclocks...*/
+	/* no long long support in the kernel :-( */
+	/* this splittig trick will work if xres > 232 */
+	var->pixclock = 1000000000/
+	(var->left_margin+var->xres+var->right_margin+var->hsync_len);
+	var->pixclock *= 1000;
+	var->pixclock /= vmode_attrs[par->vmode-1].vfreq*
+	 (var->upper_margin+var->yres+var->lower_margin+var->vsync_len);
+#else
+/* danj's */
+	/* 10^12 * clock_params[0] / (3906400 * clock_params[1] * 2^clock_params[2]) */
+	/* (10^12 * clock_params[0] / (3906400 * clock_params[1])) >> clock_params[2] */
+	/* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */
+	var->pixclock = 255990 * platinum_reg_init[par->vmode-1]->clock_params[0];
+	var->pixclock /= platinum_reg_init[par->vmode-1]->clock_params[1];
+	var->pixclock >>= platinum_reg_init[par->vmode-1]->clock_params[2];
+#endif
+}
+#else
+static inline void platinum_par_to_var(struct fb_par_platinum *par, struct fb_var_screeninfo *var)
+{
+//    FUNCID;
+	mac_vmode_to_var(par->vmode, par->cmode, var);
+}
+#endif
+
+static void platinum_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_platinum *p)
+{
+//    FUNCID;
+	memset(fix, 0, sizeof(*fix));
+	strcpy(fix->id, "platinum");
+	fix->mmio_start = (char *)p->platinum_regs_phys;
+	fix->mmio_len = 0x1000;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	
+	fix->type_aux = 0;
+	fix->ywrapstep = 0;
+	fix->xpanstep = 0;
+	fix->ypanstep = 0;
+}
+
+/* Fix must already be inited ^^^^^^^ */
+static void platinum_par_to_fix(struct fb_par_platinum *par, 
+				struct fb_fix_screeninfo *fix,
+				struct fb_info_platinum *p)
+{
+//    FUNCID;
+	fix->smem_start = (void *)(p->frame_buffer_phys);
+	fix->smem_len = platinum_vram_reqd(par->vmode, par->cmode);
+		/* Hmm, jonh used total_vram here. */
+	fix->visual = (par->cmode == CMODE_8) ?
+		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+//	fix->line_length = par->vxres << par->cmode;
+	fix->line_length = platinum_reg_init[par->vmode-1]->pitch[par->cmode];
+
+}
+
+static void platinum_init_display(struct display *disp)
+{
+	memset(disp, 0, sizeof(*disp));
+	disp->type = /* fix->type */ FB_TYPE_PACKED_PIXELS;
+	disp->can_soft_blank = 1;
+	disp->scrollmode = SCROLL_YREDRAW;
+#if 0
+		disp->type_aux = fix->type_aux;
+		disp->cmap.red = NULL;	/* ??? danj */
+		disp->cmap.green = NULL;
+		disp->cmap.blue = NULL;
+		disp->cmap.transp = NULL;
+			/* Yeah, I realize I just set 0 = 0. */
+#endif
+}
+
+static void platinum_par_to_display(struct fb_par_platinum *par,
+  struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_platinum *p)
+{
+//    FUNCID;
+	disp->var = p->var;
+	disp->screen_base = (char *) p->frame_buffer
+			  + platinum_reg_init[par->vmode-1]->fb_offset
+			  + ((par->yres % 16) / 2) * fix->line_length + 0x10;
+	disp->visual = fix->visual;
+	disp->line_length = fix->line_length;
+
+	if(disp->scrollmode != SCROLL_YREDRAW) {
+		printk(KERN_ERR "Scroll mode not YREDRAW in platinum_par_to_display!!\n");
+		disp->scrollmode = SCROLL_YREDRAW;
+	}
+
+	switch(par->cmode) {
+#ifdef FBCON_HAS_CFB8
+	 case CMODE_8:
+	    disp->dispsw = &fbcon_cfb8;
+	    break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	 case CMODE_16:
+	    disp->dispsw = &fbcon_cfb16;
+	    break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	 case CMODE_32:
+	    disp->dispsw = &fbcon_cfb32;
+	    break;
+#endif
+	 default:
+	    disp->dispsw = NULL;
+	    break;
+	}
+}
+
+static void platinum_init_info(struct fb_info *info, struct fb_info_platinum *p)
+{
+//    FUNCID;
+	strcpy(info->modename, p->fix.id);
+	info->node = -1;	/* ??? danj */
+	info->fbops = &platinumfb_ops;
+	info->disp = &p->disp;
+	info->fontname[0] = 0;
+	info->changevar = NULL;
+	info->switch_con = &platinum_switch;
+	info->updatevar = &platinum_updatevar;
+	info->blank = &platinum_blank;
+}
+
+/* danj: Oh, I HOPE I didn't miss anything major in here... */
+static void platinum_par_to_all(struct fb_info_platinum *p, int init)
+{
+//    FUNCID;
+	if(init) {
+		platinum_init_fix(&p->fix, p);
+	}
+	platinum_par_to_fix(&p->par, &p->fix, p);
+
+	platinum_par_to_var(&p->par, &p->var);
+
+	if(init) {
+		platinum_init_display(&p->disp);
+	}
+	platinum_par_to_display(&p->par, &p->disp, &p->fix, p);
+	
+	if(init) {
+		platinum_init_info(&p->info, p);
+	}
+}
+
+#if 0
+__initfunc(void platinum_setup(char *options, int *ints))
+{
+    /* Parse user speficied options (`video=platinumfb:') */
+	FUNCID;
+}
+
+#endif
+
diff -u --recursive --new-file v2.1.111/linux/drivers/video/platinumfb.h linux/drivers/video/platinumfb.h
--- v2.1.111/linux/drivers/video/platinumfb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/platinumfb.h	Sun Jul 26 14:40:19 1998
@@ -0,0 +1,399 @@
+/*
+ * linux/drivers/video/platinumfb-hw.c -- Frame buffer device for the
+ * Platinum on-board video in PowerMac 7200s (and some clones based
+ * on the same motherboard.)
+ *
+ *  Created 09 Feb 1998 by Jon Howell <jonh@cs.dartmouth.edu>
+ *
+ * Copyright (C) 1998 Jon Howell
+ *
+ *  based on drivers/macintosh/platinum.c: Console support
+ * 	for PowerMac "platinum" display adaptor.
+ *  Copyright (C) 1996 Paul Mackerras and Mark Abene.
+ *
+ *  based on skeletonfb.c:
+ *  Created 28 Dec 1997 by Geert Uytterhoeven
+ *
+ * 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.
+ */
+
+/*
+ * Structure of the registers for the DACula colormap device.
+ */
+struct cmap_regs {
+	unsigned char addr;
+	char pad1[15];
+	unsigned char d1;
+	char pad2[15];
+	unsigned char d2;
+	char pad3[15];
+	unsigned char lut;
+	char pad4[15];
+};
+
+/*
+ * Structure of the registers for the "platinum" display adaptor".
+ */
+struct preg {			/* padded register */
+	unsigned r;			/* notice this is 32 bits. */
+	char pad[12];
+};
+
+struct platinum_regs {
+	struct preg reg[128];
+};
+
+/*
+ * Register initialization tables for the platinum display.
+ *
+ * It seems that there are two different types of platinum display
+ * out there.  Older ones use the values in clocksel[1], for which
+ * the formula for the clock frequency seems to be
+ *	F = 14.3MHz * c0 / (c1 & 0x1f) / (1 << (c1 >> 5))
+ * Newer ones use the values in clocksel[0], for which the formula
+ * seems to be
+ *	F = 15MHz * c0 / ((c1 & 0x1f) + 2) / (1 << (c1 >> 5))
+ */
+struct platinum_regvals {
+	int	fb_offset;
+	int	pitch[3];
+	unsigned regs[26];
+	unsigned char offset[3];
+	unsigned char mode[3];
+	unsigned char dacula_ctrl[3];
+	unsigned char clock_params[2][2];
+};
+
+#define DIV2	0x20
+#define DIV4	0x40
+#define DIV8	0x60
+#define DIV16	0x80
+
+/* 1280x1024, 75Hz (20) */
+static struct platinum_regvals platinum_reg_init_20 = {
+	0x5c00,
+	{ 1312, 2592, 2592 },
+	{ 0xffc, 4, 0, 0, 0, 0, 0x428, 0,
+	  0, 0xb3, 0xd3, 0x12, 0x1a5, 0x23, 0x28, 0x2d,
+	  0x5e, 0x19e, 0x1a4, 0x854, 0x852, 4, 9, 0x50,
+	  0x850, 0x851 }, { 0x58, 0x5d, 0x5d },
+	{ 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 },
+	{{ 45, 3 }, { 66, 7 }}
+};
+
+/* 1280x960, 75Hz (19) */
+static struct platinum_regvals platinum_reg_init_19 = {
+	0x5c00,
+	{ 1312, 2592, 2592 },
+	{ 0xffc, 4, 0, 0, 0, 0, 0x428, 0,
+	  0, 0xb2, 0xd2, 0x12, 0x1a3, 0x23, 0x28, 0x2d,
+	  0x5c, 0x19c, 0x1a2, 0x7d0, 0x7ce, 4, 9, 0x4c,
+	  0x7cc, 0x7cd }, { 0x56, 0x5b, 0x5b },
+	{ 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 },
+	{{ 42, 3 }, { 44, 5 }}
+};
+
+/* 1152x870, 75Hz (18) */
+static struct platinum_regvals platinum_reg_init_18 = {
+	0x11b0,
+	{ 1184, 2336, 4640 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x38f, 0,
+	  0, 0x294, 0x16c, 0x20, 0x2d7, 0x3f, 0x49, 0x53,
+	  0x82, 0x2c2, 0x2d6, 0x726, 0x724, 4, 9, 0x52,
+	  0x71e, 0x722 }, { 0x74, 0x7c, 0x81 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 26, 0 + DIV2 }, { 42, 6 }}
+};
+
+/* 1024x768, 75Hz (17) */
+static struct platinum_regvals platinum_reg_init_17 = {
+	0x10b0,
+	{ 1056, 2080, 4128 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x254, 0x14b, 0x18, 0x295, 0x2f, 0x32, 0x3b,
+	  0x80, 0x280, 0x296, 0x648, 0x646, 4, 9, 0x40,
+	  0x640, 0x644 }, { 0x72, 0x7a, 0x7f },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 54, 3 + DIV2 }, { 67, 12 }}
+};
+
+/* 1024x768, 75Hz (16) */
+static struct platinum_regvals platinum_reg_init_16 = {
+	0x10b0,
+	{ 1056, 2080, 4128 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x250, 0x147, 0x17, 0x28f, 0x2f, 0x35, 0x47,
+	  0x82, 0x282, 0x28e, 0x640, 0x63e, 4, 9, 0x3c,
+	  0x63c, 0x63d }, { 0x74, 0x7c, 0x81 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 20, 0 + DIV2 }, { 11, 2 }}
+};
+
+/* 1024x768, 70Hz (15) */
+static struct platinum_regvals platinum_reg_init_15 = {
+	0x10b0,
+	{ 1056, 2080, 4128 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x254, 0x14b, 0x22, 0x297, 0x43, 0x49, 0x5b,
+	  0x86, 0x286, 0x296, 0x64c, 0x64a, 0xa, 0xf, 0x44,
+	  0x644, 0x646 }, { 0x78, 0x80, 0x85 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 19, 0 + DIV2 }, { 110, 21 }}
+};
+
+/* 1024x768, 60Hz (14) */
+static struct platinum_regvals platinum_reg_init_14 = {
+	0x10b0,
+	{ 1056, 2080, 4128 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x25a, 0x14f, 0x22, 0x29f, 0x43, 0x49, 0x5b,
+	  0x8e, 0x28e, 0x29e, 0x64c, 0x64a, 0xa, 0xf, 0x44,
+	  0x644, 0x646 }, { 0x80, 0x88, 0x8d },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 71, 6 + DIV2 }, { 118, 13 + DIV2 }}
+};
+
+/* 832x624, 75Hz (13) */
+static struct platinum_regvals platinum_reg_init_13 = {
+	0x70,
+	{ 864, 1680, 3360 },	/* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB */
+	{ 0xff0, 4, 0, 0, 0, 0, 0x299, 0,
+	  0, 0x21e, 0x120, 0x10, 0x23f, 0x1f, 0x25, 0x37,
+	  0x8a, 0x22a, 0x23e, 0x536, 0x534, 4, 9, 0x52,
+	  0x532, 0x533 }, { 0x7c, 0x84, 0x89 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }}
+};
+
+/* 800x600, 75Hz (12) */
+static struct platinum_regvals platinum_reg_init_12 = {
+	0x1010,
+	{ 832, 1632, 3232 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x1ce, 0x108, 0x14, 0x20f, 0x27, 0x30, 0x39,
+	  0x72, 0x202, 0x20e, 0x4e2, 0x4e0, 4, 9, 0x2e,
+	  0x4de, 0x4df }, { 0x64, 0x6c, 0x71 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 122, 7 + DIV4 }, { 62, 9 + DIV2 }}
+};
+
+/* 800x600, 72Hz (11) */
+static struct platinum_regvals platinum_reg_init_11 = {
+	0x1010,
+	{ 832, 1632, 3232 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x1ca, 0x104, 0x1e, 0x207, 0x3b, 0x44, 0x4d,
+	  0x56, 0x1e6, 0x206, 0x534, 0x532, 0xa, 0xe, 0x38,
+	  0x4e8, 0x4ec }, { 0x48, 0x50, 0x55 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 26, 0 + DIV4 }, { 42, 6 + DIV2 }}
+};
+
+/* 800x600, 60Hz (10) */
+static struct platinum_regvals platinum_reg_init_10 = {
+	0x1010,
+	{ 832, 1632, 3232 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d,
+	  0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34,
+	  0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 54, 3 + DIV4 }, { 95, 1 + DIV8 }}
+};
+
+/* 800x600, 56Hz (9) --unsupported? copy of mode 10 for now... */
+static struct platinum_regvals platinum_reg_init_9 = {
+	0x1010,
+	{ 832, 1632, 3232 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d,
+	  0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34,
+	  0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 54, 3 + DIV4 }, { 88, 1 + DIV8 }}
+};
+
+/* 768x576, 50Hz Interlaced-PAL (8) */
+static struct platinum_regvals platinum_reg_init_8 = {
+	0x1010,
+	{ 800, 1568, 3104 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36,
+	  0x47, 0x1c7, 0x1d6, 0x271, 0x270, 4, 9, 0x27,
+	  0x267, 0x26b }, { 0x39, 0x41, 0x46 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }}
+};
+
+/* 640x870, 75Hz Portrait (7) */
+static struct platinum_regvals platinum_reg_init_7 = {
+	0xb10,
+	{ 672, 1312, 2592 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x176, 0xd0, 0x14, 0x19f, 0x27, 0x2d, 0x3f,
+	  0x4a, 0x18a, 0x19e, 0x72c, 0x72a, 4, 9, 0x58,
+	  0x724, 0x72a }, { 0x3c, 0x44, 0x49 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }}
+};
+
+/* 640x480, 67Hz (6) */
+static struct platinum_regvals platinum_reg_init_6 = {
+	0x1010,
+	{ 672, 1312, 2592 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x209, 0,
+	  0, 0x18e, 0xd8, 0x10, 0x1af, 0x1f, 0x25, 0x37,
+	  0x4a, 0x18a, 0x1ae, 0x41a, 0x418, 4, 9, 0x52,
+	  0x412, 0x416 }, { 0x3c, 0x44, 0x49 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 99, 4 + DIV8 }, { 42, 5 + DIV4 }}
+};
+
+/* 640x480, 60Hz (5) */
+static struct platinum_regvals platinum_reg_init_5 = {
+	0x1010,
+	{ 672, 1312, 2592 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x15e, 0xc8, 0x18, 0x18f, 0x2f, 0x35, 0x3e,
+	  0x42, 0x182, 0x18e, 0x41a, 0x418, 2, 7, 0x44,
+	  0x404, 0x408 }, { 0x34, 0x3c, 0x41 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 26, 0 + DIV8 }, { 14, 2 + DIV4 }}
+};
+
+/* 640x480, 60Hz Interlaced-NTSC (4) */
+static struct platinum_regvals platinum_reg_init_4 = {
+	0x1010,
+	{ 672, 1312, 2592 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30,
+	  0x37, 0x177, 0x184, 0x20d, 0x20c, 5, 0xb, 0x23,
+	  0x203, 0x206 }, { 0x29, 0x31, 0x36 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }}
+};
+
+/* 640x480, 50Hz Interlaced-PAL (3) */
+static struct platinum_regvals platinum_reg_init_3 = {
+	0x1010,
+	{ 672, 1312, 2592 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36,
+	  0x67, 0x1a7, 0x1d6, 0x271, 0x270, 4, 9, 0x57,
+	  0x237, 0x26b }, { 0x59, 0x61, 0x66 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }}
+};
+
+/* 512x384, 60Hz (2) */
+static struct platinum_regvals platinum_reg_init_2 = {
+	0x1010,
+	{ 544, 1056, 2080 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x25c, 0x140, 0x10, 0x27f, 0x1f, 0x2b, 0x4f,
+	  0x68, 0x268, 0x27e, 0x32e, 0x32c, 4, 9, 0x2a,
+	  0x32a, 0x32b }, { 0x5a, 0x62, 0x67 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 33, 2 + DIV8 }, { 79, 9 + DIV8 }}
+};
+
+/* 512x384, 60Hz Interlaced-NTSC (1) */
+static struct platinum_regvals platinum_reg_init_1 = {
+	0x1010,
+	{ 544, 1056, 2080 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30,
+	  0x57, 0x157, 0x184, 0x20d, 0x20c, 5, 0xb, 0x53,
+	  0x1d3, 0x206 }, { 0x49, 0x51, 0x56 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }}
+};
+
+#define VMODE_MAX           20
+
+static struct platinum_regvals *platinum_reg_init[VMODE_MAX] = {
+	&platinum_reg_init_1,
+	&platinum_reg_init_2,
+	&platinum_reg_init_3,
+	&platinum_reg_init_4,
+	&platinum_reg_init_5,
+	&platinum_reg_init_6,
+	&platinum_reg_init_7,
+	&platinum_reg_init_8,
+	&platinum_reg_init_9,
+	&platinum_reg_init_10,
+	&platinum_reg_init_11,
+	&platinum_reg_init_12,
+	&platinum_reg_init_13,
+	&platinum_reg_init_14,
+	&platinum_reg_init_15,
+	&platinum_reg_init_16,
+	&platinum_reg_init_17,
+	&platinum_reg_init_18,
+	&platinum_reg_init_19,
+	&platinum_reg_init_20
+};
+
+struct vmode_attr {
+	int hres;
+	int vres;
+	int vfreq;
+	int interlaced;
+};
+
+struct vmode_attr vmode_attrs[VMODE_MAX] = {
+	{512, 384, 60, 1},
+	{512, 384, 60},
+	{640, 480, 50, 1},
+	{640, 480, 60, 1},
+	{640, 480, 60},
+	{640, 480, 67},
+	{640, 870, 75},
+	{768, 576, 50, 1},
+	{800, 600, 56},
+	{800, 600, 60},
+	{800, 600, 72},
+	{800, 600, 75},
+	{832, 624, 75},
+	{1024, 768, 60},
+	{1024, 768, 72},
+	{1024, 768, 75},
+	{1024, 768, 75},
+	{1152, 870, 75},
+	{1280, 960, 75},
+	{1280, 1024, 75}
+};
+
+/* this stuff should probably be shared by the various vmode-based	*/
+/* drivers in a vmode.h header.										*/
+
+#define VMODE_NVRAM		0	/* use value stored in nvram */
+#define VMODE_512_384_60I	1	/* 512x384, 60Hz interlaced (NTSC) */
+#define VMODE_512_384_60	2	/* 512x384, 60Hz */
+#define VMODE_640_480_50I	3	/* 640x480, 50Hz interlaced (PAL) */
+#define VMODE_640_480_60I	4	/* 640x480, 60Hz interlaced (NTSC) */
+#define VMODE_640_480_60	5	/* 640x480, 60Hz (VGA) */
+#define VMODE_640_480_67	6	/* 640x480, 67Hz */
+#define VMODE_640_870_75P	7	/* 640x870, 75Hz (portrait) */
+#define VMODE_768_576_50I	8	/* 768x576, 50Hz (PAL full frame) */
+#define VMODE_800_600_56	9	/* 800x600, 56Hz */
+#define VMODE_800_600_60	10	/* 800x600, 60Hz */
+#define VMODE_800_600_72	11	/* 800x600, 72Hz */
+#define VMODE_800_600_75	12	/* 800x600, 75Hz */
+#define VMODE_832_624_75	13	/* 832x624, 75Hz */
+#define VMODE_1024_768_60	14	/* 1024x768, 60Hz */
+#define VMODE_1024_768_70	15	/* 1024x768, 70Hz (or 72Hz?) */
+#define VMODE_1024_768_75V	16	/* 1024x768, 75Hz (VESA) */
+#define VMODE_1024_768_75	17	/* 1024x768, 75Hz */
+#define VMODE_1152_870_75	18	/* 1152x870, 75Hz */
+#define VMODE_1280_960_75	19	/* 1280x960, 75Hz */
+#define VMODE_1280_1024_75	20	/* 1280x1024, 75Hz */
+#define VMODE_MAX		20
+#define VMODE_CHOOSE		99	/* choose based on monitor sense */
+
+#define CMODE_NVRAM		-1	/* use value stored in nvram */
+#define CMODE_8			0	/* 8 bits/pixel */
+#define CMODE_16		1	/* 16 (actually 15) bits/pixel */
+#define CMODE_32		2	/* 32 (actually 24) bits/pixel */
diff -u --recursive --new-file v2.1.111/linux/drivers/video/prom.uni linux/drivers/video/prom.uni
--- v2.1.111/linux/drivers/video/prom.uni	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/prom.uni	Sun Jul 26 14:40:19 1998
@@ -0,0 +1,11 @@
+#
+# Unicode mapping table for font in Sun PROM
+# 
+#
+0x20-0x7e	idem
+0xa0-0xff	idem
+#
+0x7c		U+2502
+0x2d		U+2500
+0x2b		U+250c U+2510 U+2514 U+2518 U+251c U+2524 U+252c U+2534 U+253c
+0xa4		U+fffd
diff -u --recursive --new-file v2.1.111/linux/drivers/video/promcon.c linux/drivers/video/promcon.c
--- v2.1.111/linux/drivers/video/promcon.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/promcon.c	Sun Jul 26 14:40:19 1998
@@ -1,10 +1,11 @@
-/* $Id: promcon.c,v 1.6 1998/07/19 12:49:26 mj Exp $
+/* $Id: promcon.c,v 1.10 1998/07/24 15:31:53 jj Exp $
  * Console driver utilizing PROM sun terminal emulation
  *
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
  * Copyright (C) 1998  Jakub Jelinek  (jj@ultra.linux.cz)
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -15,15 +16,23 @@
 #include <linux/delay.h>
 #include <linux/console.h>
 #include <linux/console_struct.h>
+#include <linux/vt_kern.h>
 #include <linux/selection.h>
 #include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/kd.h>
 
 #include <asm/oplib.h>
+#include <asm/uaccess.h>
 
 static short pw = 80 - 1, ph = 34 - 1;
 static short px, py;
+static unsigned long promcon_uni_pagedir[2];
 
-#define PROMCON_COLOR 1
+extern u8 promfont_unicount[];
+extern u16 promfont_unitable[];
+
+#define PROMCON_COLOR 0
 
 #if PROMCON_COLOR
 #define inverted(s)	((((s) & 0x7700) == 0x0700) ? 0 : 1)
@@ -119,12 +128,70 @@
 	return display_desc;
 }
 
+__initfunc(static void
+promcon_init_unimap(struct vc_data *conp))
+{
+	mm_segment_t old_fs = get_fs();
+	struct unipair *p, *p1;
+	u16 *q;
+	int i, j, k;
+	
+	p = kmalloc(256*sizeof(struct unipair), GFP_KERNEL);
+	if (!p) return;
+	
+	q = promfont_unitable;
+	p1 = p;
+	k = 0;
+	for (i = 0; i < 256; i++)
+		for (j = promfont_unicount[i]; j; j--) {
+			p1->unicode = *q++;
+			p1->fontpos = i;
+			p1++;
+			k++;
+		}
+	set_fs(KERNEL_DS);
+	con_clear_unimap(conp->vc_num, NULL);
+	con_set_unimap(conp->vc_num, k, p);
+	con_protect_unimap(conp->vc_num, 1);
+	set_fs(old_fs);
+	kfree(p);
+}
+
 static void
 promcon_init(struct vc_data *conp, int init)
 {
+	unsigned long p;
+	
 	conp->vc_can_do_color = PROMCON_COLOR;
-	conp->vc_cols = pw + 1;
-	conp->vc_rows = ph + 1;
+	if (init) {
+		conp->vc_cols = pw + 1;
+		conp->vc_rows = ph + 1;
+	}
+	p = *conp->vc_uni_pagedir_loc;
+	if (conp->vc_uni_pagedir_loc == &conp->vc_uni_pagedir ||
+	    !--conp->vc_uni_pagedir_loc[1])
+		con_free_unimap(conp->vc_num);
+	conp->vc_uni_pagedir_loc = promcon_uni_pagedir;
+	promcon_uni_pagedir[1]++;
+	if (!promcon_uni_pagedir[0] && p) {
+		promcon_init_unimap(conp);
+	}
+	if (!init) {
+		if (conp->vc_cols != pw + 1 || conp->vc_rows != ph + 1)
+			vc_resize_con(ph + 1, pw + 1, conp->vc_num);
+		else if (conp->vc_num == fg_console)
+			update_screen(fg_console);
+	}
+}
+
+static void
+promcon_deinit(struct vc_data *conp)
+{
+	/* When closing the last console, reset video origin */
+	if (!--promcon_uni_pagedir[1])
+		con_free_unimap(conp->vc_num);
+	conp->vc_uni_pagedir_loc = &conp->vc_uni_pagedir;
+	con_set_default_unimap(conp->vc_num);
 }
 
 static int
@@ -482,6 +549,13 @@
 	return 0;
 }
 
+#if !(PROMCON_COLOR)
+static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
+{
+	return (_reverse) ? 0xf : 0x7;
+}
+#endif
+
 /*
  *  The console 'switch' structure for the VGA based console
  */
@@ -496,7 +570,7 @@
 struct consw prom_con = {
 	con_startup:		promcon_startup,
 	con_init:		promcon_init,
-	con_deinit:		DUMMY,
+	con_deinit:		promcon_deinit,
 	con_clear:		promcon_clear,
 	con_putc:		promcon_putc,
 	con_putcs:		promcon_putcs,
@@ -510,6 +584,18 @@
 	con_scrolldelta:	DUMMY,
 	con_set_origin:		NULL,
 	con_save_screen:	NULL,
+#if PROMCON_COLOR
 	con_build_attr:		NULL,
+#else
+	con_build_attr:		promcon_build_attr,
+#endif
 	con_invert_region:	NULL,
 };
+
+__initfunc(void prom_con_init(void))
+{
+	if (conswitchp == &dummy_con)
+		take_over_console(&prom_con, 0, MAX_NR_CONSOLES-1, 1);
+	else if (conswitchp == &prom_con)
+		promcon_init_unimap(vc_cons[fg_console].d);
+}
diff -u --recursive --new-file v2.1.111/linux/drivers/video/retz3fb.c linux/drivers/video/retz3fb.c
--- v2.1.111/linux/drivers/video/retz3fb.c	Sun Jul 26 11:57:17 1998
+++ linux/drivers/video/retz3fb.c	Sun Jul 26 14:40:19 1998
@@ -21,6 +21,7 @@
  */
 
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.111/linux/drivers/video/sbusfb.c linux/drivers/video/sbusfb.c
--- v2.1.111/linux/drivers/video/sbusfb.c	Sun Jul 26 11:57:18 1998
+++ linux/drivers/video/sbusfb.c	Sun Jul 26 14:40:19 1998
@@ -277,7 +277,7 @@
 		rects [13] = fb->var.yres_virtual - fb->y_margin;
 		rects [14] = fb->var.xres_virtual - fb->x_margin;
 		rects [15] = fb->var.yres_virtual;
-		(*fb->fill)(fb, s, 4, rects);
+		(*fb->fill)(fb, p, s, 4, rects);
 	} else {
 		unsigned char *fb_base = p->screen_base, *q;
 		int skip_bytes = fb->y_margin * fb->var.xres_virtual;
@@ -298,13 +298,13 @@
 				memset (q, ~0, size);
 		} else {
 			fb_base -= (skip_bytes + fb->x_margin);
-			memset (fb_base, attr_bg_col(s), skip_bytes - fb->x_margin);
-			memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bg_col(s), skip_bytes - fb->x_margin);
+			memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin);
+			memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bgcol(p,s), skip_bytes - fb->x_margin);
 			incr = fb->var.xres_virtual;
 			size = fb->x_margin * 2;
 			for (q = fb_base + skip_bytes - fb->x_margin, h = 0;
 			     h <= he; q += incr, h++)
-				memset (q, attr_bg_col(s), size);
+				memset (q, attr_bgcol(p,s), size);
 		}
 	}
 	if (fb->switch_from_graph)
@@ -942,6 +942,7 @@
 	
 	type->fb_height = h = prom_getintdefault(node, "height", 900);
 	type->fb_width  = w = prom_getintdefault(node, "width", 1152);
+sizechange:
 	type->fb_depth  = depth = (fbtype == FBTYPE_SUN2BW) ? 1 : 8;
 	linebytes = prom_getintdefault(node, "linebytes", w * depth / 8);
 	type->fb_size   = PAGE_ALIGN((linebytes) * h);
@@ -990,7 +991,7 @@
 	fb->cursor.hwsize.fbx = 32;
 	fb->cursor.hwsize.fby = 32;
 	
-	if (depth > 1)
+	if (depth > 1 && !fb->color_map)
 		fb->color_map = kmalloc(256 * 3, GFP_ATOMIC);
 		
 	switch(fbtype) {
@@ -1028,6 +1029,9 @@
 		kfree(fb);
 		return;
 	}
+	
+	if (p == SBUSFBINIT_SIZECHANGE)
+		goto sizechange;
 
 	disp->dispsw = &fb->dispsw;
 	if (fb->setcursor)
diff -u --recursive --new-file v2.1.111/linux/drivers/video/sbusfb.h linux/drivers/video/sbusfb.h
--- v2.1.111/linux/drivers/video/sbusfb.h	Sun Jul 26 11:57:18 1998
+++ linux/drivers/video/sbusfb.h	Sun Jul 26 14:40:19 1998
@@ -24,6 +24,18 @@
 	struct cg6_tec *tec;
 	volatile u32 *fhc;
 };
+struct fb_info_bwtwo {
+	struct bw2_regs *regs;
+};
+struct fb_info_cgthree {
+	struct cg3_regs *regs;
+};
+struct fb_info_tcx {
+	struct bt_regs *bt;
+	struct tcx_thc *thc;
+	struct tcx_tec *tec;
+	u32 *cplane;
+};
 
 struct cg_cursor {
 	short	enable;         /* cursor is enabled */
@@ -56,6 +68,9 @@
 	union {
 		struct fb_info_creator ffb;
 		struct fb_info_cgsix cg6;
+		struct fb_info_bwtwo bw2;
+		struct fb_info_cgthree cg3;
+		struct fb_info_tcx tcx;
 	} s;
 	unsigned char *color_map;
 	struct cg_cursor cursor;
@@ -81,7 +96,7 @@
 	void (*unblank)(struct fb_info_sbusfb *);
 	void (*margins)(struct fb_info_sbusfb *, struct display *, int, int);
 	void (*reset)(struct fb_info_sbusfb *);
-	void (*fill)(struct fb_info_sbusfb *, int, int, unsigned short *);
+	void (*fill)(struct fb_info_sbusfb *, struct display *, int, int, unsigned short *);
 	void (*switch_from_graph)(struct fb_info_sbusfb *);
 	void (*restore_palette)(struct fb_info_sbusfb *);
 };
@@ -94,13 +109,8 @@
 extern char *bwtwofb_init(struct fb_info_sbusfb *);
 extern char *cgfourteenfb_init(struct fb_info_sbusfb *);
 
-#define attr_fg_col(s)    \
-	(((s) >> 8) & 0x0f)
-#define attr_bg_col(s)    \
-	(((s) >> 12) & 0x0f)
-#define attr_bg_col_ec(conp) \
-	(((conp)->vc_video_erase_char >> 12) & 0x0f)
-
 #define sbusfbinfod(disp) ((struct fb_info_sbusfb *)(disp->fb_info))
 #define sbusfbinfo(info) ((struct fb_info_sbusfb *)(info))
 #define CM(i, j) [3*(i)+(j)]
+
+#define SBUSFBINIT_SIZECHANGE ((char *)-1)
diff -u --recursive --new-file v2.1.111/linux/drivers/video/skeletonfb.c linux/drivers/video/skeletonfb.c
--- v2.1.111/linux/drivers/video/skeletonfb.c	Sun Jul 26 11:57:18 1998
+++ linux/drivers/video/skeletonfb.c	Sun Jul 26 14:40:19 1998
@@ -8,6 +8,7 @@
  * for more details.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.111/linux/drivers/video/tcxfb.c linux/drivers/video/tcxfb.c
--- v2.1.111/linux/drivers/video/tcxfb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/tcxfb.c	Sun Jul 26 14:40:19 1998
@@ -0,0 +1,290 @@
+/* $Id: tcxfb.c,v 1.1 1998/07/21 14:50:44 jj Exp $
+ * tcxfb.c: TCX 24/8bit frame buffer driver
+ *
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#include <linux/module.h>
+#include <linux/sched.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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/selection.h>
+
+#include "sbusfb.h"
+#include <asm/io.h>
+
+#include "fbcon-cfb8.h"
+
+/* THC definitions */
+#define TCX_THC_MISC_REV_SHIFT       16
+#define TCX_THC_MISC_REV_MASK        15
+#define TCX_THC_MISC_VSYNC_DIS       (1 << 25)
+#define TCX_THC_MISC_HSYNC_DIS       (1 << 24)
+#define TCX_THC_MISC_RESET           (1 << 12)
+#define TCX_THC_MISC_VIDEO           (1 << 10)
+#define TCX_THC_MISC_SYNC            (1 << 9)
+#define TCX_THC_MISC_VSYNC           (1 << 8)
+#define TCX_THC_MISC_SYNC_ENAB       (1 << 7)
+#define TCX_THC_MISC_CURS_RES        (1 << 6)
+#define TCX_THC_MISC_INT_ENAB        (1 << 5)
+#define TCX_THC_MISC_INT             (1 << 4)
+#define TCX_THC_MISC_INIT            0x9f
+#define TCX_THC_REV_REV_SHIFT        20
+#define TCX_THC_REV_REV_MASK         15
+#define TCX_THC_REV_MINREV_SHIFT     28
+#define TCX_THC_REV_MINREV_MASK      15
+
+/* The contents are unknown */
+struct tcx_tec {
+	volatile u32 tec_matrix;
+	volatile u32 tec_clip;
+	volatile u32 tec_vdc;
+};
+
+struct tcx_thc {
+	volatile u32 thc_rev;
+        u32 thc_pad0[511];
+	volatile u32 thc_hs;		/* hsync timing */
+	volatile u32 thc_hsdvs;
+	volatile u32 thc_hd;
+	volatile u32 thc_vs;		/* vsync timing */
+	volatile u32 thc_vd;
+	volatile u32 thc_refresh;
+	volatile u32 thc_misc;
+	u32 thc_pad1[56];
+	volatile u32 thc_cursxy;	/* cursor x,y position (16 bits each) */
+	volatile u32 thc_cursmask[32];	/* cursor mask bits */
+	volatile u32 thc_cursbits[32];	/* what to show where mask enabled */
+};
+
+static struct sbus_mmap_map tcx_mmap_map[] = {
+	{ TCX_RAM8BIT,		0,		SBUS_MMAP_FBSIZE(1) },
+	{ TCX_RAM24BIT,		0,		SBUS_MMAP_FBSIZE(4) },
+	{ TCX_UNK3,		0,		SBUS_MMAP_FBSIZE(8) },
+	{ TCX_UNK4,		0,		SBUS_MMAP_FBSIZE(8) },
+	{ TCX_CONTROLPLANE,	0,		SBUS_MMAP_FBSIZE(4) },
+	{ TCX_UNK6,		0,		SBUS_MMAP_FBSIZE(8) },
+	{ TCX_UNK7,		0,		SBUS_MMAP_FBSIZE(8) },
+	{ TCX_TEC,		0,		PAGE_SIZE	    },
+	{ TCX_BTREGS,		0,		PAGE_SIZE	    },
+	{ TCX_THC,		0,		PAGE_SIZE	    },
+	{ TCX_DHC,		0,		PAGE_SIZE	    },
+	{ TCX_ALT,		0,		PAGE_SIZE	    },
+	{ TCX_UNK2,		0,		0x20000		    },
+	{ 0,			0,		0		    }
+};
+
+static void tcx_set_control_plane (struct fb_info_sbusfb *fb)
+{
+	u32 *p, *pend;
+        
+	p = fb->s.tcx.cplane;
+	if (!p) return;
+	for (pend = p + fb->type.fb_size; p < pend; p++)
+		*p &= 0xffffff;
+}
+                                                
+static void tcx_switch_from_graph (struct fb_info_sbusfb *fb)
+{
+	/* Reset control plane to 8bit mode if necessary */
+	if (fb->open && fb->mmaped)
+		tcx_set_control_plane (fb);
+}
+
+static void tcx_loadcmap (struct fb_info_sbusfb *fb, int index, int count)
+{
+	struct bt_regs *bt = fb->s.tcx.bt;
+	int i;
+                
+	bt->addr = index << 24;
+	for (i = index; count--; i++){
+		bt->color_map = fb->color_map CM(i,0) << 24;
+		bt->color_map = fb->color_map CM(i,1) << 24;
+		bt->color_map = fb->color_map CM(i,2) << 24;
+	}
+}
+
+static void tcx_restore_palette (struct fb_info_sbusfb *fb)
+{
+	struct bt_regs *bt = fb->s.tcx.bt;
+                
+	bt->addr = 0;
+	bt->color_map = 0xffffffff;
+	bt->color_map = 0xffffffff;
+	bt->color_map = 0xffffffff;
+}
+
+static void tcx_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
+{
+        struct bt_regs *bt = fb->s.tcx.bt;
+
+	/* Note the 2 << 24 is different from cg6's 1 << 24 */
+	bt->addr = 2 << 24;
+	bt->cursor = red[0] << 24;
+	bt->cursor = green[0] << 24;
+	bt->cursor = blue[0] << 24;
+	bt->addr = 3 << 24;
+	bt->cursor = red[1] << 24;
+	bt->cursor = green[1] << 24;
+	bt->cursor = blue[1] << 24;
+	bt->addr = 0;
+}
+
+/* Set cursor shape */
+static void tcx_setcurshape (struct fb_info_sbusfb *fb)
+{
+	struct tcx_thc *thc = fb->s.tcx.thc;
+	int i;
+
+	for (i = 0; i < 32; i++){
+		thc->thc_cursmask [i] = fb->cursor.bits[0][i];
+		thc->thc_cursbits [i] = fb->cursor.bits[1][i];
+	}
+}
+
+/* Load cursor information */
+static void tcx_setcursor (struct fb_info_sbusfb *fb)
+{
+	unsigned int v;
+	struct cg_cursor *c = &fb->cursor;
+
+	if (c->enable)
+		v = ((c->cpos.fbx - c->chot.fbx) << 16)
+		    |((c->cpos.fby - c->chot.fby) & 0xffff);
+	else
+		/* Magic constant to turn off the cursor */
+		v = ((65536-32) << 16) | (65536-32);
+	fb->s.tcx.thc->thc_cursxy = v;
+}
+
+static void tcx_blank (struct fb_info_sbusfb *fb)
+{
+	fb->s.tcx.thc->thc_misc &= ~TCX_THC_MISC_VIDEO;
+	/* This should put us in power-save */
+	fb->s.tcx.thc->thc_misc |= TCX_THC_MISC_VSYNC_DIS;
+        fb->s.tcx.thc->thc_misc |= TCX_THC_MISC_HSYNC_DIS;
+}
+
+static void tcx_unblank (struct fb_info_sbusfb *fb)
+{
+	fb->s.tcx.thc->thc_misc &= ~TCX_THC_MISC_VSYNC_DIS;
+	fb->s.tcx.thc->thc_misc &= ~TCX_THC_MISC_HSYNC_DIS;
+	fb->s.tcx.thc->thc_misc |= TCX_THC_MISC_VIDEO;
+}
+
+static void tcx_reset (struct fb_info_sbusfb *fb)
+{
+	if (fb->open && fb->mmaped)
+		tcx_set_control_plane(fb);
+	
+	/* Turn off stuff in the Transform Engine. */
+	fb->s.tcx.tec->tec_matrix = 0;
+	fb->s.tcx.tec->tec_clip = 0;
+	fb->s.tcx.tec->tec_vdc = 0;
+
+	/* Enable cursor in Brooktree DAC. */
+	fb->s.tcx.bt->addr = 0x06 << 24;
+	fb->s.tcx.bt->control |= 0x03 << 24;
+}
+
+static void tcx_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
+{
+	p->screen_base += (y_margin - fb->y_margin) * p->line_length + (x_margin - fb->x_margin);
+}
+
+static char idstring[60] __initdata = { 0 };
+
+__initfunc(char *tcxfb_init(struct fb_info_sbusfb *fb))
+{
+	struct fb_fix_screeninfo *fix = &fb->fix;
+	struct display *disp = &fb->disp;
+	struct fbtype *type = &fb->type;
+	unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr;
+	int lowdepth;
+
+#ifndef FBCON_HAS_CFB8
+	return NULL;
+#endif
+
+	lowdepth = prom_getbool (fb->prom_node, "tcx-8-bit");
+	
+	if (lowdepth) {
+		strcpy(fb->info.modename, "TCX8");
+		strcpy(fix->id, "TCX8");
+	} else {
+		strcpy(fb->info.modename, "TCX24");
+		strcpy(fix->id, "TCX24");
+	}
+	fix->line_length = fb->var.xres_virtual;
+	
+	disp->scrollmode = SCROLL_YREDRAW;
+	if (!disp->screen_base)
+		disp->screen_base = (char *)sparc_alloc_io(phys, 0, 
+			type->fb_size, "tcx_ram", fb->iospace, 0);
+	disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin;
+	fb->s.tcx.tec = (struct tcx_tec *)sparc_alloc_io(fb->sbdp->reg_addrs[7].phys_addr, 0, 
+			sizeof(struct tcx_tec), "tcx_tec", fb->iospace, 0);
+	fb->s.tcx.thc = (struct tcx_thc *)sparc_alloc_io(fb->sbdp->reg_addrs[9].phys_addr, 0, 
+			sizeof(struct tcx_thc), "tcx_thc", fb->iospace, 0);
+	fb->s.tcx.bt = (struct bt_regs *)sparc_alloc_io(fb->sbdp->reg_addrs[8].phys_addr, 0, 
+			sizeof(struct bt_regs), "tcx_dac", fb->iospace, 0);
+	if (!lowdepth) {
+		fb->s.tcx.cplane = (u32 *)sparc_alloc_io(fb->sbdp->reg_addrs[4].phys_addr, 0, 
+				type->fb_size*4, "tcx_cplane", fb->iospace, 0);
+		type->fb_depth = 24;
+		fb->switch_from_graph = tcx_switch_from_graph;
+	} else {
+		/* As there can be one tcx in a machine only, we can write directly into
+		   tcx_mmap_map */
+		tcx_mmap_map[1].size = SBUS_MMAP_EMPTY;
+		tcx_mmap_map[4].size = SBUS_MMAP_EMPTY;
+		tcx_mmap_map[5].size = SBUS_MMAP_EMPTY;
+		tcx_mmap_map[6].size = SBUS_MMAP_EMPTY;
+	}
+	fb->dispsw = fbcon_cfb8;
+
+	fb->margins = tcx_margins;
+	fb->loadcmap = tcx_loadcmap;
+	if (prom_getbool (fb->prom_node, "hw-cursor")) {
+		fb->setcursor = tcx_setcursor;
+		fb->setcursormap = tcx_setcursormap;
+		fb->setcurshape = tcx_setcurshape;
+	}
+	fb->restore_palette = tcx_restore_palette;
+	fb->blank = tcx_blank;
+	fb->unblank = tcx_unblank;
+	fb->reset = tcx_reset;
+	
+	fb->physbase = 0;
+	fb->mmap_map = tcx_mmap_map;
+	
+	/* Initialize Brooktree DAC */
+	fb->s.tcx.bt->addr = 0x04 << 24;         /* color planes */
+	fb->s.tcx.bt->control = 0xff << 24;
+	fb->s.tcx.bt->addr = 0x05 << 24;
+	fb->s.tcx.bt->control = 0x00 << 24;
+	fb->s.tcx.bt->addr = 0x06 << 24;         /* overlay plane */
+	fb->s.tcx.bt->control = 0x73 << 24;
+	fb->s.tcx.bt->addr = 0x07 << 24;
+	fb->s.tcx.bt->control = 0x00 << 24;
+	
+	sprintf(idstring, "tcx at %x.%08lx Rev %d.%d %s", fb->iospace, phys,
+		    (fb->s.tcx.thc->thc_rev >> TCX_THC_REV_REV_SHIFT) & TCX_THC_REV_REV_MASK,
+                    (fb->s.tcx.thc->thc_rev >> TCX_THC_REV_MINREV_SHIFT) & TCX_THC_REV_MINREV_MASK,
+		    lowdepth ? "8-bit only" : "24-bit depth");
+		    
+	tcx_reset(fb);
+		    
+	return idstring;
+}
diff -u --recursive --new-file v2.1.111/linux/drivers/video/tgafb.c linux/drivers/video/tgafb.c
--- v2.1.111/linux/drivers/video/tgafb.c	Sun Jul 26 11:57:18 1998
+++ linux/drivers/video/tgafb.c	Sun Jul 26 14:40:19 1998
@@ -22,6 +22,7 @@
  * KNOWN PROBLEMS/TO DO ==================================================== */
 
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.1.111/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- v2.1.111/linux/drivers/video/vesafb.c	Sun Jul 26 11:57:18 1998
+++ linux/drivers/video/vesafb.c	Sun Jul 26 14:40:19 1998
@@ -8,6 +8,7 @@
  *
  */ 
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.111/linux/drivers/video/vfb.c linux/drivers/video/vfb.c
--- v2.1.111/linux/drivers/video/vfb.c	Sun Jul 26 11:57:18 1998
+++ linux/drivers/video/vfb.c	Sun Jul 26 14:40:19 1998
@@ -8,6 +8,7 @@
  *  more details.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.111/linux/drivers/video/vgacon.c linux/drivers/video/vgacon.c
--- v2.1.111/linux/drivers/video/vgacon.c	Sun Jul 26 11:57:18 1998
+++ linux/drivers/video/vgacon.c	Sun Jul 26 23:34:35 1998
@@ -33,7 +33,7 @@
  *  more details.
  */
 
-#include <linux/config.h>
+
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
@@ -94,6 +94,7 @@
 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines);
 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse);
 static void vgacon_invert_region(struct vc_data *c, u16 *p, int count);
+static unsigned long vgacon_uni_pagedir[2];
 
 
 /* Description of the hardware situation */
@@ -292,16 +293,23 @@
 	return display_desc;
 }
 
-static int vga_use_count;
-
 static void vgacon_init(struct vc_data *c, int init)
 {
+	unsigned long p;
+	
 	/* We cannot be loaded as a module, therefore init is always 1 */
 	c->vc_can_do_color = vga_can_do_color;
 	c->vc_cols = vga_video_num_columns;
 	c->vc_rows = vga_video_num_lines;
 	c->vc_complement_mask = 0x7700;
-	vga_use_count++;
+	p = *c->vc_uni_pagedir_loc;
+	if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
+	    !--c->vc_uni_pagedir_loc[1])
+		con_free_unimap(c->vc_num);
+	c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
+	vgacon_uni_pagedir[1]++;
+	if (!vgacon_uni_pagedir[0] && p)
+		con_set_default_unimap(c->vc_num);
 }
 
 static inline void vga_set_mem_top(struct vc_data *c)
@@ -312,10 +320,13 @@
 static void vgacon_deinit(struct vc_data *c)
 {
 	/* When closing the last console, reset video origin */
-	if (!--vga_use_count) {
+	if (!--vgacon_uni_pagedir[1]) {
 		c->vc_visible_origin = vga_vram_base;
 		vga_set_mem_top(c);
+		con_free_unimap(c->vc_num);
 	}
+	c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
+	con_set_default_unimap(c->vc_num);
 }
 
 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse)
@@ -345,15 +356,19 @@
 
 static void vgacon_invert_region(struct vc_data *c, u16 *p, int count)
 {
-	int col = vga_can_do_color;
-
-	while (count--) {
-		u16 a = *p;
-		if (col)
-			a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
-		else
+	if (vga_can_do_color) {
+		while (count--) {
+			u16 a = scr_readw(p);
+			a = (((a) & 0x88ff) | (((a) & 0x7000) >> 4)
+			     | (((a) & 0x0700) << 4));
+			scr_writew(a, p++);
+		}
+	} else {
+		while (count--) {
+			u16 a = scr_readw(p);
 			a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
-		*p++ = a;
+			scr_writew(a, p++);
+		}
 	}
 }
 
@@ -862,6 +877,7 @@
 		op->width = 8;
 		op->height = vga_video_font_height;
 		op->charcount = vga_512_chars ? 512 : 256;
+		if (!op->data) return 0;
 		rc = vgacon_do_font_op(op->data, 0, 0);
 	} else
 		rc = -ENOSYS;
diff -u --recursive --new-file v2.1.111/linux/drivers/video/virgefb.c linux/drivers/video/virgefb.c
--- v2.1.111/linux/drivers/video/virgefb.c	Sun Jul 26 11:57:18 1998
+++ linux/drivers/video/virgefb.c	Sun Jul 26 14:40:19 1998
@@ -16,6 +16,7 @@
 
 #undef VIRGEFBDEBUG
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.111/linux/fs/Config.in linux/fs/Config.in
--- v2.1.111/linux/fs/Config.in	Wed Jun 24 22:54:08 1998
+++ linux/fs/Config.in	Sun Jul 26 01:20:22 1998
@@ -66,7 +66,7 @@
 if [ "$CONFIG_AFFS_FS" != "n" ]; then
   define_bool CONFIG_AMIGA_PARTITION y
 fi
-tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS
+tristate 'UFS filesystem support' CONFIG_UFS_FS
 if [ "$CONFIG_UFS_FS" != "n" ]; then
   bool 'BSD disklabel (FreeBSD partition tables) support' CONFIG_BSD_DISKLABEL
   bool 'SMD disklabel (Sun partition tables) support' CONFIG_SMD_DISKLABEL
diff -u --recursive --new-file v2.1.111/linux/fs/open.c linux/fs/open.c
--- v2.1.111/linux/fs/open.c	Thu May 14 19:47:43 1998
+++ linux/fs/open.c	Tue Jul 28 11:14:41 1998
@@ -674,6 +674,7 @@
 	if (f->f_mode & FMODE_WRITE)
 		put_write_access(inode);
 cleanup_dentry:
+	f->f_dentry = NULL;
 	dput(dentry);
 cleanup_file:
 	put_filp(f);
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/Makefile linux/fs/ufs/Makefile
--- v2.1.111/linux/fs/ufs/Makefile	Wed Jun 24 22:54:10 1998
+++ linux/fs/ufs/Makefile	Sun Jul 26 01:20:22 1998
@@ -8,8 +8,8 @@
 # Note 2! The CFLAGS definitions are now in the main makefile.
 
 O_TARGET := ufs.o
-O_OBJS   := ufs_dir.o ufs_file.o ufs_inode.o ufs_namei.o \
-		ufs_super.o ufs_symlink.o ufs_swab.o
+O_OBJS   := acl.o balloc.o cylinder.o dir.o file.o ialloc.o inode.o \
+		namei.o super.o symlink.o truncate.o util.o
 M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/acl.c linux/fs/ufs/acl.c
--- v2.1.111/linux/fs/ufs/acl.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/ufs/acl.c	Sun Jul 26 01:20:22 1998
@@ -0,0 +1,66 @@
+/*
+ *  linux/fs/ufs/acl.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles Uiversity, Faculty of Mathematics and Physics
+ *
+ *  from
+ *
+ *  linux/fs/ext2/acl.c
+ *
+ * Copyright (C) 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ */
+
+/*
+ * This file will contain the Access Control Lists management for the
+ * second extended file system.
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+
+/*
+ * ufs_permission ()
+ *
+ * Check for access rights
+ */
+int ufs_permission (struct inode * inode, int mask)
+{
+	unsigned short mode = inode->i_mode;
+
+	/*
+	 * Nobody gets write access to a file on a readonly-fs
+	 */
+	if ((mask & S_IWOTH) && 
+            (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) &&
+            IS_RDONLY(inode))
+		return -EROFS;
+	/*
+	 * Nobody gets write access to an immutable file
+	 */
+	if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
+		return -EACCES;
+
+	/*
+	 * If no ACL, checks using the file mode
+	 */
+	else if (current->fsuid == inode->i_uid)
+		mode >>= 6;
+	else if (in_group_p (inode->i_gid))
+		mode >>= 3;
+	/*
+	 * Access is always granted for root. We now check last,
+         * though, for BSD process accounting correctness
+	 */
+	if (((mode & mask & S_IRWXO) == mask) || fsuser())
+		return 0;
+	else
+		return -EACCES;
+}
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/balloc.c linux/fs/ufs/balloc.c
--- v2.1.111/linux/fs/ufs/balloc.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/ufs/balloc.c	Sun Jul 26 01:20:22 1998
@@ -0,0 +1,792 @@
+/*
+ *  linux/fs/ufs/balloc.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ */
+
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
+#include <asm/bitops.h>
+#include <asm/byteorder.h>
+
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_BALLOC_DEBUG
+#undef UFS_BALLOC_DEBUG_MORE
+
+#ifdef UFS_BALLOC_DEBUG
+#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+#ifdef UFS_BALLOC_DEBUG_MORE
+#define UFSDM \
+ufs_print_cylinder_stuff (ucg, swab); \
+printk("inode: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nifree), \
+swab32(sb->fs_cs(ucpi->c_cgx).cs_nifree), SWAB32(ucg->cg_cs.cs_nifree)); \
+printk("block: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nbfree), \
+SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nbfree), SWAB32(ucg->cg_cs.cs_nbfree)); \
+printk("fragment: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nffree), \
+SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nffree), SWAB32(ucg->cg_cs.cs_nffree)); \
+printk("ndir: total %u, fs %u, cg %u\n\n", SWAB32(usb1->fs_cstotal.cs_ndir), \
+SWAB32(sb->fs_cs(ucpi->c_cgx).cs_ndir), SWAB32(ucg->cg_cs.cs_ndir));
+#else
+#define UFSDM
+#endif
+
+
+unsigned ufs_add_fragments (struct inode *, unsigned, unsigned, unsigned, int *);
+unsigned ufs_alloc_fragments (struct inode *, unsigned, unsigned, unsigned, int *);
+unsigned ufs_alloccg_block (struct inode *, struct ufs_cg_private_info *, unsigned, int *);
+unsigned ufs_bitmap_search (struct super_block *, struct ufs_cg_private_info *, unsigned, unsigned);
+static unsigned char ufs_fragtable_8fpb[], ufs_fragtable_other[];
+
+/*
+ * Free 'count' fragments from fragment number 'fragment'
+ */
+void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count) {
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block_first * usb1;
+	struct ufs_cg_private_info * ucpi;
+	struct ufs_cylinder_group * ucg;
+	unsigned cgno, bit, end_bit, bbase, blkmap, i, blkno, cylno;
+	unsigned swab;
+	
+	sb = inode->i_sb;
+	uspi = sb->u.ufs_sb.s_uspi;
+	swab = sb->u.ufs_sb.s_swab;
+	usb1 = ubh_get_usb_first(USPI_UBH);
+	
+	UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
+	
+	if (ufs_fragnum(fragment) + count > uspi->s_fpg)
+		ufs_error (sb, "ufs_free_fragments", "internal error");
+	
+	lock_super(sb);
+	
+	cgno = ufs_dtog(fragment);
+	bit = ufs_dtogd(fragment);
+	if (cgno >= uspi->s_ncg) {
+		ufs_panic (sb, "ufs_free_fragments", "freeing blocks are outside device");
+		goto failed;
+	}
+		
+	ucpi = ufs_load_cylinder (sb, cgno);
+	if (!ucpi) 
+		goto failed;
+	ucg = ubh_get_ucg (UCPI_UBH);
+	if (!ufs_cg_chkmagic (ucg)) {
+		ufs_panic (sb, "ufs_free_fragments", "internal error, bad magic number on cg %u", cgno);
+		goto failed;
+	}
+
+	UFSDM
+	
+	end_bit = bit + count;
+	bbase = ufs_blknum (bit);
+	blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase);
+	ufs_fragacct (sb, blkmap, ucg->cg_frsum, -1);
+	for (i = bit; i < end_bit; i++) {
+		if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, i))
+			ubh_setbit (UCPI_UBH, ucpi->c_freeoff, i);
+		else ufs_error (sb, "ufs_free_fragments",
+			"bit already cleared for fragment %u", i);
+	}
+	
+	DQUOT_FREE_BLOCK (sb, inode, count);
+	ADD_SWAB32(ucg->cg_cs.cs_nffree, count);
+	ADD_SWAB32(usb1->fs_cstotal.cs_nffree, count);
+	ADD_SWAB32(sb->fs_cs(cgno).cs_nffree, count);
+	blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase);
+	ufs_fragacct(sb, blkmap, ucg->cg_frsum, 1);
+
+	/*
+	 * Trying to reasembly free fragments into block
+	 */
+	blkno = ufs_fragstoblks (bbase);
+	if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) {
+		SUB_SWAB32(ucg->cg_cs.cs_nffree, uspi->s_fpb);
+		SUB_SWAB32(usb1->fs_cstotal.cs_nffree, uspi->s_fpb);
+		SUB_SWAB32(sb->fs_cs(cgno).cs_nffree, uspi->s_fpb);
+		INC_SWAB32(ucg->cg_cs.cs_nbfree);
+		INC_SWAB32(usb1->fs_cstotal.cs_nbfree);
+		INC_SWAB32(sb->fs_cs(cgno).cs_nbfree);
+		cylno = ufs_cbtocylno (bbase);
+		INC_SWAB16(ubh_cg_blks (ucpi, cylno, ufs_cbtorpos(bbase)));
+		INC_SWAB32(ubh_cg_blktot (ucpi, cylno));
+	}
+	
+	UFSDM
+	
+	ubh_mark_buffer_dirty (USPI_UBH, 1);
+	ubh_mark_buffer_dirty (UCPI_UBH, 1);
+	if (sb->s_flags & MS_SYNCHRONOUS) {
+		ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
+		ubh_wait_on_buffer (UCPI_UBH);
+        }
+	sb->s_dirt = 1;
+	
+	unlock_super (sb);
+	UFSD(("EXIT\n"))
+	return;
+
+failed:
+	unlock_super (sb);
+	UFSD(("EXIT (FAILED)\n"))
+	return;
+}
+
+/*
+ * Free 'count' fragments from fragment number 'fragment' (free whole blocks)
+ */
+void ufs_free_blocks (struct inode * inode, unsigned fragment, unsigned count) {
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block_first * usb1;
+	struct ufs_cg_private_info * ucpi;
+	struct ufs_cylinder_group * ucg;
+	unsigned overflow, cgno, bit, end_bit, blkno, i, cylno;
+	unsigned swab;
+	
+	sb = inode->i_sb;
+	uspi = sb->u.ufs_sb.s_uspi;
+	swab = sb->u.ufs_sb.s_swab;
+	usb1 = ubh_get_usb_first(USPI_UBH);
+
+	UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
+	
+	if ((fragment & uspi->s_fpbmask) || (count & uspi->s_fpbmask)) {
+		ufs_error (sb, "ufs_free_blocks", "internal error");
+		goto failed;
+	}
+
+	lock_super(sb);
+	
+do_more:
+	overflow = 0;
+	cgno = ufs_dtog (fragment);
+	bit = ufs_dtogd (fragment);
+	if (cgno >= uspi->s_ncg) {
+		ufs_panic (sb, "ufs_free_blocks", "freeing blocks are outside device");
+		goto failed;
+	}
+	end_bit = bit + count;
+	if (end_bit > uspi->s_fpg) {
+		overflow = bit + count - uspi->s_fpg;
+		count -= overflow;
+		end_bit -= overflow;
+	}
+
+	ucpi = ufs_load_cylinder (sb, cgno);
+	if (!ucpi) 
+		goto failed;
+	ucg = ubh_get_ucg (UCPI_UBH);
+	if (!ufs_cg_chkmagic (ucg)) {
+		ufs_panic (sb, "ufs_free_blocks", "internal error, bad magic number on cg %u", cgno);
+		goto failed;
+	}
+
+	UFSDM
+	
+	for (i = bit; i < end_bit; i += uspi->s_fpb) {
+		blkno = ufs_fragstoblks(i);
+		if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) {
+			ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
+		}
+		ubh_setblock(UCPI_UBH, ucpi->c_freeoff, blkno);
+		DQUOT_FREE_BLOCK(sb, inode, uspi->s_fpb);
+		INC_SWAB32(ucg->cg_cs.cs_nbfree);
+		INC_SWAB32(usb1->fs_cstotal.cs_nbfree);
+		INC_SWAB32(sb->fs_cs(cgno).cs_nbfree);
+		cylno = ufs_cbtocylno(i);
+		INC_SWAB16(ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(i)));
+		INC_SWAB32(ubh_cg_blktot(ucpi, cylno));
+  	}
+
+	UFSDM
+	
+	ubh_mark_buffer_dirty (USPI_UBH, 1);
+	ubh_mark_buffer_dirty (UCPI_UBH, 1);
+	if (sb->s_flags & MS_SYNCHRONOUS) {
+		ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
+		ubh_wait_on_buffer (UCPI_UBH);
+        }
+
+	if (overflow) {
+		fragment += count;
+		count = overflow;
+		goto do_more;
+	}
+
+	sb->s_dirt = 1;
+	unlock_super (sb);
+	UFSD(("EXIT\n"))
+	return;
+
+failed:
+	unlock_super (sb);
+	UFSD(("EXIT (FAILED)\n"))
+	return;
+}
+
+
+
+#define NULLIFY_FRAGMENTS \
+	for (i = oldcount; i < newcount; i++) { \
+		bh = getblk (sb->s_dev, result + i, sb->s_blocksize); \
+		memset (bh->b_data, 0, sb->s_blocksize); \
+		mark_buffer_uptodate(bh, 1); \
+		mark_buffer_dirty (bh, 1); \
+		if (IS_SYNC(inode)) { \
+			ll_rw_block (WRITE, 1, &bh); \
+  			wait_on_buffer (bh); \
+		} \
+		brelse (bh); \
+	}
+
+unsigned ufs_new_fragments (struct inode * inode, u32 * p, unsigned fragment,
+	unsigned goal, unsigned count, int * err )
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block_first * usb1;
+	struct buffer_head * bh;
+	unsigned cgno, oldcount, newcount, tmp, request, i, result;
+	unsigned swab;
+	
+	UFSD(("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count))
+	
+	sb = inode->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+	usb1 = ubh_get_usb_first(USPI_UBH);
+	*err = -ENOSPC;
+
+	lock_super (sb);
+	
+	tmp = SWAB32(*p);
+	if (count + ufs_fragnum(fragment) > uspi->s_fpb) {
+		ufs_warning (sb, "ufs_new_fragments", "internal warning"
+			" fragment %u, count %u", fragment, count);
+		count = uspi->s_fpb - ufs_fragnum(fragment); 
+	}
+	oldcount = ufs_fragnum (fragment);
+	newcount = oldcount + count;
+
+	/*
+	 * Somebody else has just allocated our fragments
+	 */
+	if (oldcount) {
+		if (!tmp) {
+			ufs_error (sb, "ufs_new_fragments", "internal error, "
+				"fragment %u, tmp %u\n", fragment, tmp);
+			return (unsigned)-1;
+		}
+		if (fragment < inode->u.ufs_i.i_lastfrag) {
+			UFSD(("EXIT (ALREADY ALLOCATED)\n"))
+			printk("hlaska 2\n");
+			unlock_super (sb);
+			return 0;
+		}
+	}
+	else {
+		if (tmp) {
+			UFSD(("EXIT (ALREADY ALLOCATED)\n"))
+			printk("hlaska 3, fragment %u, tmp %u, oldcount %u\n", fragment, tmp, oldcount);
+			unlock_super(sb);
+			return 0;
+		}
+	}
+	
+	/*
+	 * There is not enough space for user on the device
+	 */
+	if (!fsuser() && ufs_freespace(usb1, UFS_MINFREE) <= 0) {
+		unlock_super (sb);
+		UFSD(("EXIT (FAILED)\n"))
+		return 0;
+	} 
+	
+	if (goal >= uspi->s_size) 
+		goal = 0;
+	if (goal == 0) 
+		cgno = ufs_inotocg (inode->i_ino);
+	else
+		cgno = ufs_dtog (goal);
+	 
+	/*
+	 * allocate new fragment
+	 */
+	if (oldcount == 0) {
+	        result = ufs_alloc_fragments (inode, cgno, goal, count, err);
+		if (result) {
+			*p = SWAB32(result);
+			*err = 0;
+			inode->i_blocks += count << uspi->s_nspfshift;
+			inode->u.ufs_i.i_lastfrag = max (inode->u.ufs_i.i_lastfrag, fragment + count);
+			NULLIFY_FRAGMENTS
+		}
+		unlock_super(sb);
+		UFSD(("EXIT, result %u\n", result))
+		return result;
+	}
+
+	/*
+	 * resize block
+	 */
+	result = ufs_add_fragments (inode, tmp, oldcount, newcount, err);
+	if (result) {
+		*err = 0;
+		inode->i_blocks += count << uspi->s_nspfshift;
+		inode->u.ufs_i.i_lastfrag = max (inode->u.ufs_i.i_lastfrag, fragment + count);
+		NULLIFY_FRAGMENTS
+		unlock_super(sb);
+		UFSD(("EXIT, result %u\n", result))
+		return result;
+	}
+
+	/*
+	 * allocate new block and move data
+	 */
+	switch (SWAB32(usb1->fs_optim)) {
+	    case UFS_OPTSPACE:
+		request = newcount;
+		if (uspi->s_minfree < 5 || SWAB32(usb1->fs_cstotal.cs_nffree) 
+		    > uspi->s_dsize * uspi->s_minfree / (2 * 100) )
+			break;
+		usb1->fs_optim = SWAB32(UFS_OPTTIME);
+		break;
+	    default:
+		usb1->fs_optim = SWAB32(UFS_OPTTIME);
+	
+	    case UFS_OPTTIME:
+		request = uspi->s_fpb;
+		if (SWAB32(usb1->fs_cstotal.cs_nffree) < uspi->s_dsize *
+		    (uspi->s_minfree - 2) / 100)
+		    	break;
+		usb1->fs_optim = SWAB32(UFS_OPTSPACE);
+		break;
+	}
+	result = ufs_alloc_fragments (inode, cgno, goal, request, err);
+	if (result) {
+		for (i = 0; i < oldcount; i++) {
+			bh = bread (sb->s_dev, tmp + i, sb->s_blocksize);
+			mark_buffer_clean (bh);
+			bh->b_blocknr = result + i;
+			mark_buffer_dirty (bh, 0);
+			if (IS_SYNC(inode)) {
+				ll_rw_block (WRITE, 1, &bh);
+				wait_on_buffer (bh);
+			}
+			brelse (bh);
+		}
+		*p = SWAB32(result);
+		*err = 0;
+		inode->i_blocks += count << uspi->s_nspfshift;
+		inode->u.ufs_i.i_lastfrag = max (inode->u.ufs_i.i_lastfrag, fragment + count);
+		NULLIFY_FRAGMENTS
+		unlock_super(sb);
+		if (newcount < request)
+			ufs_free_fragments (inode, result + newcount, request - newcount);
+		ufs_free_fragments (inode, tmp, oldcount);
+		UFSD(("EXIT, result %u\n", result))
+		return result;
+	}
+
+	unlock_super(sb);
+	UFSD(("EXIT (FAILED)\n"))
+	return 0;
+}		
+
+unsigned ufs_add_fragments (struct inode * inode, unsigned fragment,
+	unsigned oldcount, unsigned newcount, int * err)
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block_first * usb1;
+	struct ufs_cg_private_info * ucpi;
+	struct ufs_cylinder_group * ucg;
+	unsigned cgno, fragno, fragoff, count, fragsize, i;
+	unsigned swab;
+	
+	UFSD(("ENTER, fragment %u, oldcount %u, newcount %u\n", fragment, oldcount, newcount))
+	
+	sb = inode->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+	usb1 = ubh_get_usb_first (USPI_UBH);
+	count = newcount - oldcount;
+	
+	cgno = ufs_dtog(fragment);
+	if (sb->fs_cs(cgno).cs_nffree < count)
+		return 0;
+	if ((ufs_fragnum (fragment) + newcount) > uspi->s_fpb)
+		return 0;
+	ucpi = ufs_load_cylinder (sb, cgno);
+	if (!ucpi)
+		return 0;
+	ucg = ubh_get_ucg (UCPI_UBH);
+	if (!ufs_cg_chkmagic(ucg)) {
+		ufs_panic (sb, "ufs_add_fragments",
+			"internal error, bad magic number on cg %u", cgno);
+		return 0;
+	}
+
+	UFSDM
+	
+	fragno = ufs_dtogd (fragment);
+	fragoff = ufs_fragnum (fragno);
+	for (i = oldcount; i < newcount; i++)
+		if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, fragno + i))
+			return 0;
+	/*
+	 * Block can be extended
+	 */
+	ucg->cg_time = SWAB32(CURRENT_TIME);
+	for (i = newcount; i < (uspi->s_fpb - fragoff); i++)
+		if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, fragno + i))
+			break;
+	fragsize = i - oldcount;
+	if (!SWAB32(ucg->cg_frsum[fragsize]))
+		ufs_panic (sb, "ufs_add_fragments",
+			"internal error or corruted bitmap on cg %u", cgno);
+	DEC_SWAB32(ucg->cg_frsum[fragsize]);
+	if (fragsize != count)
+		INC_SWAB32(ucg->cg_frsum[fragsize - count]);
+	for (i = oldcount; i < newcount; i++)
+		ubh_clrbit (UCPI_UBH, ucpi->c_freeoff, fragno + i);
+	if(DQUOT_ALLOC_BLOCK(sb, inode, count)) {
+		*err = -EDQUOT;
+		return 0;
+	}
+	SUB_SWAB32(ucg->cg_cs.cs_nffree, count);
+	SUB_SWAB32(sb->fs_cs(cgno).cs_nffree, count);
+	SUB_SWAB32(usb1->fs_cstotal.cs_nffree, count);
+	usb1->fs_fmod = SWAB32(1);
+	
+	UFSDM
+	
+	ubh_mark_buffer_dirty (USPI_UBH, 1);
+	ubh_mark_buffer_dirty (UCPI_UBH, 1);
+	if (sb->s_flags & MS_SYNCHRONOUS) {
+		ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
+		ubh_wait_on_buffer (UCPI_UBH);
+	}
+	sb->s_dirt = 1;
+
+	UFSD(("EXIT, fragment %u\n", fragment))
+	
+	return fragment;
+}
+
+#define UFS_TEST_FREE_SPACE_CG \
+	ucg = (struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[cgno]->b_data; \
+	if (SWAB32(ucg->cg_cs.cs_nbfree)) \
+		goto cg_found; \
+	for (k = count; k < uspi->s_fpb; k++) \
+		if (SWAB32(ucg->cg_frsum[k])) \
+			goto cg_found; 
+
+unsigned ufs_alloc_fragments (struct inode * inode, unsigned cgno,
+	unsigned goal, unsigned count, int * err)
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block_first * usb1;
+	struct ufs_cg_private_info * ucpi;
+	struct ufs_cylinder_group * ucg;
+	unsigned oldcg, i, j, k, result, allocsize;
+	unsigned swab;
+	
+	UFSD(("ENTER, ino %lu, cgno %u, goal %u, count %u\n", inode->i_ino, cgno, goal, count))
+
+	sb = inode->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+	usb1 = ubh_get_usb_first(USPI_UBH);
+	oldcg = cgno;
+	
+	/*
+	 * 1. searching on preferred cylinder group
+	 */
+	UFS_TEST_FREE_SPACE_CG
+
+	/*
+	 * 2. quadratic rehash
+	 */
+	for (j = 1; j < uspi->s_ncg; j *= 2) {
+		cgno += j;
+		if (cgno >= uspi->s_ncg) 
+			cgno -= uspi->s_ncg;
+		UFS_TEST_FREE_SPACE_CG
+	}
+
+	/*
+ 	 * 3. brute force search
+	 * We start at i = 2 ( 0 is checked at 1.step, 1 at 2.step )
+	 */
+	cgno = (oldcg + 1) % uspi->s_ncg;
+	for (j = 2; j < uspi->s_ncg; j++) {
+		cgno++;
+		if (cgno >= uspi->s_ncg)
+			cgno = 0;
+		UFS_TEST_FREE_SPACE_CG
+	}
+	
+	UFSD(("EXIT (FAILED)\n"))
+	return 0;
+
+cg_found:
+	ucpi = ufs_load_cylinder (sb, cgno);
+	if (!ucpi)
+		return 0;
+	ucg = ubh_get_ucg (UCPI_UBH);
+	if (!ufs_cg_chkmagic(ucg)) 
+		ufs_panic (sb, "ufs_alloc_fragments",
+			"internal error, bad magic number on cg %u", cgno);
+	ucg->cg_time = SWAB32(CURRENT_TIME);
+
+	UFSDM
+	
+	if (count == uspi->s_fpb) {
+		result = ufs_alloccg_block (inode, ucpi, goal, err);
+		if (result == (unsigned)-1)
+			return 0;
+		goto succed;
+	}
+
+	for (allocsize = count; allocsize < uspi->s_fpb; allocsize++)
+		if (SWAB32(ucg->cg_frsum[allocsize]) != 0)
+			break;
+	
+	if (allocsize == uspi->s_fpb) {
+		result = ufs_alloccg_block (inode, ucpi, goal, err);
+		if (result == (unsigned)-1)
+			return 0;
+		goal = ufs_dtogd (result);
+		for (i = count; i < uspi->s_fpb; i++)
+			ubh_setbit (UCPI_UBH, ucpi->c_freeoff, goal + i);
+		i = uspi->s_fpb - count;
+		DQUOT_FREE_BLOCK(sb, inode, i);
+		ADD_SWAB32(ucg->cg_cs.cs_nffree, i);
+		ADD_SWAB32(usb1->fs_cstotal.cs_nffree, i);
+		ADD_SWAB32(sb->fs_cs(cgno).cs_nffree, i);
+		INC_SWAB32(ucg->cg_frsum[i]);
+		goto succed;
+	}
+
+	result = ufs_bitmap_search (sb, ucpi, goal, allocsize);
+	if (result == (unsigned)-1)
+		return 0;
+	if(DQUOT_ALLOC_BLOCK(sb, inode, count)) {
+		*err = -EDQUOT;
+		return 0;
+	}
+	for (i = 0; i < count; i++)
+		ubh_clrbit (UCPI_UBH, ucpi->c_freeoff, result + i);
+	SUB_SWAB32(ucg->cg_cs.cs_nffree, count);
+	SUB_SWAB32(usb1->fs_cstotal.cs_nffree, count);
+	SUB_SWAB32(sb->fs_cs(cgno).cs_nffree, count);
+	DEC_SWAB32(ucg->cg_frsum[allocsize]);
+	if (count != allocsize)
+		INC_SWAB32(ucg->cg_frsum[allocsize - count]);
+
+succed:
+	usb1->fs_fmod = SWAB32(1);
+	
+	UFSDM
+	
+	ubh_mark_buffer_dirty (USPI_UBH, 1);
+	ubh_mark_buffer_dirty (UCPI_UBH, 1);
+	if (sb->s_flags & MS_SYNCHRONOUS) {
+		ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi);
+		ubh_wait_on_buffer (UCPI_UBH);
+	}
+	sb->s_dirt = 1;
+
+	result += cgno * uspi->s_fpg;
+	UFSD(("EXIT3, result %u\n", result))
+	return result;
+}
+
+unsigned ufs_alloccg_block (struct inode * inode,
+	struct ufs_cg_private_info * ucpi, unsigned goal, int * err)
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block_first * usb1;
+	struct ufs_cylinder_group * ucg;
+	unsigned result, cylno, blkno;
+	unsigned swab;
+
+	UFSD(("ENTER, goal %u\n", goal))
+
+	sb = inode->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+	usb1 = ubh_get_usb_first(USPI_UBH);
+	ucg = ubh_get_ucg(UCPI_UBH);
+
+	if (goal == 0) {
+		goal = ucpi->c_rotor;
+		goto norot;
+	}
+	goal = ufs_blknum (goal);
+ 	goal = ufs_dtogd (goal);
+	
+	/*
+	 * If the requested block is available, use it.
+	 */
+	if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, ufs_fragstoblks(goal))) {
+		result = goal;
+		goto gotit;
+	}
+	
+	/*** This function should be optimalized later ***/
+
+norot:	
+	result = ufs_bitmap_search (sb, ucpi, goal, uspi->s_fpb);
+	if (result == (unsigned)-1)
+		return (unsigned)-1;
+	ucpi->c_rotor = result;
+gotit:
+	blkno = ufs_fragstoblks(result);
+	ubh_clrblock(UCPI_UBH, ucpi->c_freeoff, blkno);
+	if(DQUOT_ALLOC_BLOCK(sb, inode, uspi->s_fpb)) {
+		*err = -EDQUOT;
+		return (unsigned)-1;
+	}
+	DEC_SWAB32(ucg->cg_cs.cs_nbfree);
+	DEC_SWAB32(usb1->fs_cstotal.cs_nbfree);
+	DEC_SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nbfree);
+	cylno = ufs_cbtocylno(result);
+	DEC_SWAB16(ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(result)));
+	DEC_SWAB32(ubh_cg_blktot(ucpi, cylno));
+	usb1->fs_fmod = 1;
+	
+	UFSD(("EXIT, result %u\n", result))
+
+	return result;
+}
+
+unsigned ufs_bitmap_search (struct super_block * sb,
+	struct ufs_cg_private_info * ucpi, unsigned goal, unsigned count)
+{
+	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block_first * usb1;
+	struct ufs_cylinder_group * ucg;
+	unsigned start, length, length2, location, result;
+	unsigned possition, fragsize, blockmap, mask;
+	unsigned swab;
+	
+	UFSD(("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count))
+
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+	usb1 = ubh_get_usb_first (USPI_UBH);
+	ucg = ubh_get_ucg(UCPI_UBH);
+
+	if (goal)
+		start = ufs_dtogd(goal) >> 3;
+	else
+		start = ucpi->c_frotor >> 3;
+		
+	length = howmany(uspi->s_fpg, 8) - start;
+	location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff + start, length,
+		(uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
+		1 << (count - 1 + (uspi->s_fpb & 7))); 
+	if (location == 0) {
+		length2 = start + 1;
+		location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff, length2, 
+			(uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
+			1 << (count - 1 + (uspi->s_fpb & 7)));
+		if (location == 0) {
+			ufs_error (sb, "ufs_bitmap_search",
+			"bitmap corrupted on cg %u, start %u, length %u, count %u, freeoff %u\n",
+			ucpi->c_cgx, start, length, count, ucpi->c_freeoff);
+			return (unsigned)-1;
+		}
+		start = 0;
+		length = length2;
+	}
+	result = (start + length - location) << 3;
+	ucpi->c_frotor = result;
+
+	/*
+	 * found the byte in the map
+	 */
+	blockmap = ubh_blkmap(UCPI_UBH, ucpi->c_freeoff, result);
+	fragsize = 0;
+	for (possition = 0, mask = 1; possition < 8; possition++, mask <<= 1) {
+		if (blockmap & mask) {
+			if (!(possition & uspi->s_fpbmask))
+				fragsize = 1;
+			else 
+				fragsize++;
+		}
+		else {
+			if (fragsize == count) {
+				result += possition - count;
+				UFSD(("EXIT, result %u\n", result))
+				return result;
+			}
+			fragsize = 0;
+		}
+	}
+	if (fragsize == count) {
+		result += possition - count;
+		UFSD(("EXIT, result %u\n", result))
+		return result;
+	}
+	ufs_error (sb, "ufs_bitmap_search", "block not in map on cg %u\n", ucpi->c_cgx);
+	UFSD(("EXIT (FAILED)\n"))
+	return (unsigned)-1;
+}
+
+static unsigned char ufs_fragtable_8fpb[] = {
+	0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08,
+	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10,
+	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
+	0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20,
+	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,	
+	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
+	0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A,
+	0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x08, 0x09, 0x09, 0x0A, 0x10, 0x11, 0x20, 0x40,
+	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
+	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
+	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
+	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21,
+	0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A,
+	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0A, 0x12,
+	0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0C,
+	0x08, 0x09, 0x09, 0x0A, 0x09, 0x09, 0x0A, 0x0C, 0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80,
+};
+
+static unsigned char ufs_fragtable_other[] = {
+	0x00, 0x16, 0x16, 0x2A, 0x16, 0x16, 0x26, 0x4E, 0x16, 0x16, 0x16, 0x3E, 0x2A, 0x3E, 0x4E, 0x8A,
+	0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
+	0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
+	0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA,
+	0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
+	0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
+	0x26, 0x36, 0x36, 0x2E, 0x36, 0x36, 0x26, 0x6E, 0x36, 0x36, 0x36, 0x3E, 0x2E, 0x3E, 0x6E, 0xAE,
+	0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE,
+	0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
+	0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
+	0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
+	0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE,
+	0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA,
+	0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E,	0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE,
+	0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE,
+	0x8A, 0x9E, 0x9E, 0xAA, 0x9E, 0x9E, 0xAE, 0xCE, 0x9E, 0x9E, 0x9E, 0xBE, 0xAA, 0xBE, 0xCE, 0x8A,
+};
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/cylinder.c linux/fs/ufs/cylinder.c
--- v2.1.111/linux/fs/ufs/cylinder.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/ufs/cylinder.c	Sun Jul 26 01:20:22 1998
@@ -0,0 +1,212 @@
+/*
+ *  linux/fs/ufs/cylinder.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ *
+ *  ext2 - inode (block) bitmap caching inspired
+ */
+
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+
+#include <asm/bitops.h>
+#include <asm/byteorder.h>
+
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_CYLINDER_DEBUG
+#undef UFS_CYLINDER_DEBUG_MORE
+
+#ifdef UFS_CYLINDER_DEBUG
+#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+
+/*
+ * Read cylinder group into cache. The memory space for ufs_cg_private_info
+ * structure is already allocated during ufs_read_super.
+ */
+static void ufs_read_cylinder (struct super_block * sb,
+	unsigned cgno, unsigned bitmap_nr)
+{
+	struct ufs_sb_private_info * uspi;
+	struct ufs_cg_private_info * ucpi;
+	struct ufs_cylinder_group * ucg;
+	unsigned i, j;
+	unsigned swab;
+
+	UFSD(("ENTER, cgno %u, bitmap_nr %u\n", cgno, bitmap_nr))
+	swab = sb->u.ufs_sb.s_swab;	
+	uspi = sb->u.ufs_sb.s_uspi;
+	ucpi = sb->u.ufs_sb.s_ucpi[bitmap_nr];
+	ucg = (struct ufs_cylinder_group *)sb->u.ufs_sb.s_ucg[cgno]->b_data;
+
+#ifdef UFS_CYLINDER_DEBUG_MORE
+	ufs_print_cylinder_stuff (ucg, swab);
+#endif
+
+	UCPI_UBH->fragment = ufs_cgcmin(cgno);
+	UCPI_UBH->count = uspi->s_cgsize >> sb->s_blocksize_bits;
+	/*
+	 * We have already the first fragment of cylinder group block in buffer
+	 */
+	UCPI_UBH->bh[0] = sb->u.ufs_sb.s_ucg[cgno];
+	for (i = 1; i < UCPI_UBH->count; i++)
+		if (!(UCPI_UBH->bh[i] = bread (sb->s_dev, UCPI_UBH->fragment + i, sb->s_blocksize)))
+			goto failed;
+	sb->u.ufs_sb.s_cgno[bitmap_nr] = cgno;
+			
+	ucpi->c_cgx = SWAB32(ucg->cg_cgx);
+	ucpi->c_ncyl = SWAB16(ucg->cg_ncyl);
+	ucpi->c_niblk = SWAB16(ucg->cg_niblk);
+	ucpi->c_ndblk = SWAB32(ucg->cg_ndblk);
+	ucpi->c_rotor = SWAB32(ucg->cg_rotor);
+	ucpi->c_frotor = SWAB32(ucg->cg_frotor);
+	ucpi->c_irotor = SWAB32(ucg->cg_irotor);
+	ucpi->c_btotoff = SWAB32(ucg->cg_btotoff);
+	ucpi->c_boff = SWAB32(ucg->cg_boff);
+	ucpi->c_iusedoff = SWAB32(ucg->cg_iusedoff);
+	ucpi->c_freeoff = SWAB32(ucg->cg_freeoff);
+	ucpi->c_nextfreeoff = SWAB32(ucg->cg_nextfreeoff);
+	
+	UFSD(("EXIT\n"))
+	return;	
+	
+failed:
+	for (j = 1; j < i; j++)
+		brelse (sb->u.ufs_sb.s_ucg[j]);
+	sb->u.ufs_sb.s_cgno[bitmap_nr] = UFS_CGNO_EMPTY;
+	ufs_error (sb, "ufs_read_cylinder", "can't read cylinder group block %u", cgno);
+}
+
+/*
+ * Remove cylinder group from cache, does'n release memory
+ * allocated for cylinder group (this is done at ufs_put_super only).
+ */
+void ufs_put_cylinder (struct super_block * sb, unsigned bitmap_nr)
+{
+	struct ufs_sb_private_info * uspi; 
+	struct ufs_cg_private_info * ucpi;
+	struct ufs_cylinder_group * ucg;
+	unsigned i;
+	unsigned swab;
+
+	UFSD(("ENTER, bitmap_nr %u\n", bitmap_nr))
+
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+	if (sb->u.ufs_sb.s_cgno[bitmap_nr] == UFS_CGNO_EMPTY) {
+		UFSD(("EXIT\n"))
+		return;
+	}
+	ucpi = sb->u.ufs_sb.s_ucpi[bitmap_nr];
+	ucg = ubh_get_ucg(UCPI_UBH);
+
+	if (uspi->s_ncg > UFS_MAX_GROUP_LOADED && bitmap_nr >= sb->u.ufs_sb.s_cg_loaded) {
+		ufs_panic (sb, "ufs_put_cylinder", "internal error");
+		return;
+	}
+	/*
+	 * rotor is not so important data, so we put it to disk 
+	 * at the end of working with cylinder
+	 */
+	ucg->cg_rotor = SWAB32(ucpi->c_rotor);
+	ucg->cg_frotor = SWAB32(ucpi->c_frotor);
+	ucg->cg_irotor = SWAB32(ucpi->c_irotor);
+	ubh_mark_buffer_dirty (UCPI_UBH, 1);
+	for (i = 1; i < UCPI_UBH->count; i++) {
+		brelse (UCPI_UBH->bh[i]);
+	}
+
+	sb->u.ufs_sb.s_cgno[bitmap_nr] = UFS_CGNO_EMPTY;
+	UFSD(("EXIT\n"))
+}
+
+/*
+ * Find cylinder group in cache and return it as pointer.
+ * If cylinder group is not in cache, we will load it from disk.
+ *
+ * The cache is managed by LRU alghoritm. 
+ */
+struct ufs_cg_private_info * ufs_load_cylinder (
+	struct super_block * sb, unsigned cgno)
+{
+	struct ufs_sb_private_info * uspi;
+	struct ufs_cg_private_info * ucpi;
+	unsigned cg, i, j;
+
+	UFSD(("ENTER, cgno %u\n", cgno))
+
+	uspi = sb->u.ufs_sb.s_uspi;
+	if (cgno >= uspi->s_ncg) {
+		ufs_panic (sb, "ufs_load_cylinder", "internal error, high number of cg");
+		return NULL;
+	}
+	/*
+	 * Cylinder group number cg it in cache and it was last used
+	 */
+	if (sb->u.ufs_sb.s_cgno[0] == cgno) {
+		UFSD(("EXIT\n"))
+		return sb->u.ufs_sb.s_ucpi[0];
+	}
+	/*
+	 * Number of cylinder groups is not higher than UFS_MAX_GROUP_LOADED
+	 */
+	if (uspi->s_ncg <= UFS_MAX_GROUP_LOADED) {
+		if (sb->u.ufs_sb.s_cgno[cgno] != UFS_CGNO_EMPTY) {
+			if (sb->u.ufs_sb.s_cgno[cgno] != cgno) {
+				ufs_panic (sb, "ufs_load_cylinder", "internal error, wrog number of cg in cache");
+				UFSD(("EXIT (FAILED)\n"))
+				return NULL;
+			}
+			else {
+				UFSD(("EXIT\n"))
+				return sb->u.ufs_sb.s_ucpi[cgno];
+			}
+		} else {
+			ufs_read_cylinder (sb, cgno, cgno);
+			UFSD(("EXIT\n"))
+			return sb->u.ufs_sb.s_ucpi[cgno];
+		}
+	}
+	/*
+	 * Cylinder group number cg is in cache but it was not last used, 
+	 * we will move to the first position
+	 */
+	for (i = 0; i < sb->u.ufs_sb.s_cg_loaded && sb->u.ufs_sb.s_cgno[i] != cgno; i++);
+	if (i < sb->u.ufs_sb.s_cg_loaded && sb->u.ufs_sb.s_cgno[i] == cgno) {
+		cg = sb->u.ufs_sb.s_cgno[i];
+		ucpi = sb->u.ufs_sb.s_ucpi[i];
+		for (j = i; j > 0; j--) {
+			sb->u.ufs_sb.s_cgno[j] = sb->u.ufs_sb.s_cgno[j-1];
+			sb->u.ufs_sb.s_ucpi[j] = sb->u.ufs_sb.s_ucpi[j-1];
+		}
+		sb->u.ufs_sb.s_cgno[0] = cg;
+		sb->u.ufs_sb.s_ucpi[0] = ucpi;
+	/*
+	 * Cylinder group number cg is not in cache, we will read it from disk
+	 * and put it to the first possition
+	 */
+	} else {
+		if (sb->u.ufs_sb.s_cg_loaded < UFS_MAX_GROUP_LOADED)
+			sb->u.ufs_sb.s_cg_loaded++;
+		else
+			ufs_put_cylinder (sb, UFS_MAX_GROUP_LOADED-1);
+		for (j = sb->u.ufs_sb.s_cg_loaded - 1; j > 0; j--) {
+			sb->u.ufs_sb.s_cgno[j] = sb->u.ufs_sb.s_cgno[j-1];
+			sb->u.ufs_sb.s_ucpi[j] = sb->u.ufs_sb.s_ucpi[j-1];
+		}
+		ufs_read_cylinder (sb, cgno, 0);
+	}
+	UFSD(("EXIT\n"))
+	return sb->u.ufs_sb.s_ucpi[0];
+}
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/dir.c linux/fs/ufs/dir.c
--- v2.1.111/linux/fs/ufs/dir.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/ufs/dir.c	Sun Jul 26 01:20:22 1998
@@ -0,0 +1,228 @@
+/*
+ *  linux/fs/ufs/ufs_dir.c
+ *
+ * Copyright (C) 1996
+ * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
+ * Laboratory for Computer Science Research Computing Facility
+ * Rutgers, The State University of New Jersey
+ *
+ * swab support by Francois-Rene Rideau <rideau@ens.fr> 19970406
+ *
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
+ *
+ * write support by Daniel Pirkl <daniel.pirkl@email.cz> 1998
+ */
+
+#include <linux/fs.h>
+
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_DIR_DEBUG
+
+#ifdef UFS_DIR_DEBUG
+#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+/*
+ * This is blatantly stolen from ext2fs
+ */
+static int
+ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
+{
+	struct inode *inode = filp->f_dentry->d_inode;
+	int error = 0;
+	unsigned long offset, lblk, blk;
+	int i, stored;
+	struct buffer_head * bh;
+	struct ufs_dir_entry * de;
+	struct super_block * sb;
+	int de_reclen;
+	unsigned flags, swab;
+
+
+	/* Isn't that already done in the upper layer???
+         * the VFS layer really needs some explicit documentation!
+         */
+	if (!inode || !S_ISDIR(inode->i_mode))
+		return -EBADF;
+
+	sb = inode->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+        flags = sb->u.ufs_sb.s_flags;
+
+	UFSD(("ENTER, ino %lu  f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos))
+
+	stored = 0;
+	bh = NULL;
+	offset = filp->f_pos & (sb->s_blocksize - 1);
+
+	while (!error && !stored && filp->f_pos < inode->i_size) {
+		lblk = (filp->f_pos) >> sb->s_blocksize_bits;
+	        /* XXX - ufs_bmap() call needs error checking */
+	        blk = ufs_bmap(inode, lblk);
+		bh = bread (sb->s_dev, blk, sb->s_blocksize);
+		if (!bh) {
+	                /* XXX - error - skip to the next block */
+	                printk("ufs_readdir: "
+			       "dir inode %lu has a hole at offset %lu\n",
+	                       inode->i_ino, (unsigned long int)filp->f_pos);
+			filp->f_pos += sb->s_blocksize - offset;
+			continue;
+		}
+
+revalidate:
+		/* If the dir block has changed since the last call to
+		 * readdir(2), then we might be pointing to an invalid
+		 * dirent right now.  Scan from the start of the block
+		 * to make sure. */
+		if (filp->f_version != inode->i_version) {
+			for (i = 0; i < sb->s_blocksize && i < offset; ) {
+				de = (struct ufs_dir_entry *)(bh->b_data + i);
+				/* It's too expensive to do a full
+				 * dirent test each time round this
+				 * loop, but we do have to test at
+				 * least that it is non-zero.  A
+				 * failure will be detected in the
+				 * dirent test below. */
+				de_reclen = SWAB16(de->d_reclen);
+				if (de_reclen < 1)
+					break;
+				i += de_reclen;
+			}
+			offset = i;
+			filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
+				| offset;
+			filp->f_version = inode->i_version;
+		}
+
+		while (!error && filp->f_pos < inode->i_size
+		       && offset < sb->s_blocksize) {
+			de = (struct ufs_dir_entry *) (bh->b_data + offset);
+	                /* XXX - put in a real ufs_check_dir_entry() */
+	                if ((de->d_reclen == 0) || (ufs_namlen(de) == 0)) {
+			/* SWAB16() was unneeded -- compare to 0 */
+	                        filp->f_pos = (filp->f_pos &
+				              (sb->s_blocksize - 1)) +
+				               sb->s_blocksize;
+	                        brelse(bh);
+	                        return stored;
+	                }
+#if 0 /* XXX */
+			if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
+			/* XXX - beware about de having to be swabped somehow */
+						   bh, offset)) {
+				/* On error, skip the f_pos to the
+	                           next block. */
+				filp->f_pos = (filp->f_pos &
+				              (sb->s_blocksize - 1)) +
+					       sb->s_blocksize;
+				brelse (bh);
+				return stored;
+			}
+#endif /* XXX */
+			offset += SWAB16(de->d_reclen);
+			if (de->d_ino) {
+			/* SWAB16() was unneeded -- compare to 0 */
+				/* We might block in the next section
+				 * if the data destination is
+				 * currently swapped out.  So, use a
+				 * version stamp to detect whether or
+				 * not the directory has been modified
+				 * during the copy operation. */
+				unsigned long version = inode->i_version;
+
+				UFSD(("filldir(%s,%u)\n", de->d_name, SWAB32(de->d_ino)))
+				UFSD(("namlen %u\n", ufs_namlen(de)))
+				error = filldir(dirent, de->d_name, ufs_namlen(de),
+				                filp->f_pos, SWAB32(de->d_ino));
+				if (error)
+					break;
+				if (version != inode->i_version)
+					goto revalidate;
+				stored ++;
+			}
+			filp->f_pos += SWAB16(de->d_reclen);
+		}
+		offset = 0;
+		brelse (bh);
+	}
+	UPDATE_ATIME(inode);
+	return 0;
+}
+
+int ufs_check_dir_entry (const char * function,	struct inode * dir,
+	struct ufs_dir_entry * de, struct buffer_head * bh, 
+	unsigned long offset)
+{
+	struct super_block * sb;
+	const char * error_msg;
+	unsigned flags, swab;
+	
+	sb = dir->i_sb;
+	flags = sb->u.ufs_sb.s_flags;
+	swab = sb->u.ufs_sb.s_swab;
+	error_msg = NULL;
+			
+	if (SWAB16(de->d_reclen) < UFS_DIR_REC_LEN(1))
+		error_msg = "reclen is smaller than minimal";
+	else if (SWAB16(de->d_reclen) % 4 != 0)
+		error_msg = "reclen % 4 != 0";
+	else if (SWAB16(de->d_reclen) < UFS_DIR_REC_LEN(ufs_namlen(de)))
+		error_msg = "reclen is too small for namlen";
+	else if (dir && ((char *) de - bh->b_data) + SWAB16(de->d_reclen) >
+		 dir->i_sb->s_blocksize)
+		error_msg = "directory entry across blocks";
+	else if (dir && SWAB32(de->d_ino) > (sb->u.ufs_sb.s_uspi->s_ipg * sb->u.ufs_sb.s_uspi->s_ncg))
+		error_msg = "inode out of bounds";
+
+	if (error_msg != NULL)
+		ufs_error (sb, function, "bad entry in directory #%lu, size %lu: %s - "
+			    "offset=%lu, inode=%lu, reclen=%d, namlen=%d",
+			    dir->i_ino, dir->i_size, error_msg, offset,
+			    (unsigned long) SWAB32(de->d_ino),
+			    SWAB16(de->d_reclen), ufs_namlen(de));
+	
+	return (error_msg == NULL ? 1 : 0);
+}
+
+static struct file_operations ufs_dir_operations = {
+	NULL,			/* lseek */
+	NULL,			/* read */
+	NULL,			/* write */
+	ufs_readdir,		/* readdir */
+	NULL,			/* select */
+	NULL,			/* ioctl */
+	NULL,			/* mmap */
+	NULL,			/* open */
+	NULL,			/* release */
+	file_fsync,		/* fsync */
+	NULL,			/* fasync */
+	NULL,			/* check_media_change */
+	NULL,			/* revalidate */
+};
+
+struct inode_operations ufs_dir_inode_operations = {
+	&ufs_dir_operations,	/* default directory file operations */
+	ufs_create,		/* create */
+	ufs_lookup,		/* lookup */
+	ufs_link,		/* link */
+	ufs_unlink,		/* unlink */
+	ufs_symlink,		/* symlink */
+	ufs_mkdir,		/* mkdir */
+	ufs_rmdir,		/* rmdir */
+	ufs_mknod,		/* mknod */
+	ufs_rename,		/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	ufs_bmap,		/* bmap */
+	ufs_truncate,		/* truncate */
+	ufs_permission,		/* permission */
+	NULL,			/* smap */
+};
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/file.c linux/fs/ufs/file.c
--- v2.1.111/linux/fs/ufs/file.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/ufs/file.c	Sun Jul 26 01:20:22 1998
@@ -0,0 +1,281 @@
+/*
+ *  linux/fs/ufs/file.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ *
+ *  from
+ *
+ *  linux/fs/ext2/file.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/fs/minix/file.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  ext2 fs regular file handling primitives
+ */
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/locks.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+
+#define	NBUF	32
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+
+static long long ufs_file_lseek(struct file *, long long, int);
+static ssize_t ufs_file_write (struct file *, const char *, size_t, loff_t *);
+static int ufs_release_file (struct inode *, struct file *);
+
+/*
+ * We have mostly NULL's here: the current defaults are ok for
+ * the ufs filesystem.
+ */
+static struct file_operations ufs_file_operations = {
+	ufs_file_lseek,	/* lseek */
+	generic_file_read,	/* read */
+	ufs_file_write, 	/* write */
+	NULL,			/* readdir - bad */
+	NULL,			/* poll - default */
+	NULL, 			/* ioctl */
+	generic_file_mmap,	/* mmap */
+	NULL,			/* no special open is needed */
+	ufs_release_file,	/* release */
+	NULL, 			/* fsync */
+	NULL,			/* fasync */
+	NULL,			/* check_media_change */
+	NULL			/* revalidate */
+};
+
+struct inode_operations ufs_file_inode_operations = {
+	&ufs_file_operations,/* default file operations */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	generic_readpage,	/* readpage */
+	NULL,			/* writepage */
+	ufs_bmap,		/* bmap */
+	ufs_truncate,		/* truncate */
+	NULL, 			/* permission */
+	NULL			/* smap */
+};
+
+/*
+ * Make sure the offset never goes beyond the 32-bit mark..
+ */
+static long long ufs_file_lseek(
+	struct file *file,
+	long long offset,
+	int origin )
+{
+	long long retval;
+	struct inode *inode = file->f_dentry->d_inode;
+
+	switch (origin) {
+		case 2:
+			offset += inode->i_size;
+			break;
+		case 1:
+			offset += file->f_pos;
+	}
+	retval = -EINVAL;
+	/* make sure the offset fits in 32 bits */
+	if (((unsigned long long) offset >> 32) == 0) {
+		if (offset != file->f_pos) {
+			file->f_pos = offset;
+			file->f_reada = 0;
+			file->f_version = ++event;
+		}
+		retval = offset;
+	}
+	return retval;
+}
+
+static inline void remove_suid(struct inode *inode)
+{
+	unsigned int mode;
+
+	/* set S_IGID if S_IXGRP is set, and always set S_ISUID */
+	mode = (inode->i_mode & S_IXGRP)*(S_ISGID/S_IXGRP) | S_ISUID;
+
+	/* was any of the uid bits set? */
+	mode &= inode->i_mode;
+	if (mode && !suser()) {
+		inode->i_mode &= ~mode;
+		mark_inode_dirty(inode);
+	}
+}
+
+static ssize_t ufs_file_write (
+	struct file * filp,
+	const char * buf,
+	size_t count,
+	loff_t *ppos )
+{
+	struct inode * inode = filp->f_dentry->d_inode;
+	__u32 pos;
+	long block;
+	int offset;
+	int written, c;
+	struct buffer_head * bh, *bufferlist[NBUF];
+	struct super_block * sb;
+	int err;
+	int i,buffercount,write_error;
+
+	/* POSIX: mtime/ctime may not change for 0 count */
+	if (!count)
+		return 0;
+	write_error = buffercount = 0;
+	if (!inode)
+		return -EINVAL;
+	sb = inode->i_sb;
+	if (sb->s_flags & MS_RDONLY)
+		/*
+		 * This fs has been automatically remounted ro because of errors
+		 */
+		return -ENOSPC;
+
+	if (!S_ISREG(inode->i_mode)) {
+		ufs_warning (sb, "ufs_file_write", "mode = %07o",
+			      inode->i_mode);
+		return -EINVAL;
+	}
+	remove_suid(inode);
+
+	if (filp->f_flags & O_APPEND)
+		pos = inode->i_size;
+	else {
+		pos = *ppos;
+		if (pos != *ppos)
+			return -EINVAL;
+	}
+
+	/* Check for overflow.. */
+	if (pos > (__u32) (pos + count)) {
+		count = ~pos; /* == 0xFFFFFFFF - pos */
+		if (!count)
+			return -EFBIG;
+	}
+
+	/*
+	 * If a file has been opened in synchronous mode, we have to ensure
+	 * that meta-data will also be written synchronously.  Thus, we
+	 * set the i_osync field.  This field is tested by the allocation
+	 * routines.
+	 */
+	if (filp->f_flags & O_SYNC)
+		inode->u.ufs_i.i_osync++;
+	block = pos >> sb->s_blocksize_bits;
+	offset = pos & (sb->s_blocksize - 1);
+	c = sb->s_blocksize - offset;
+	written = 0;
+	do {
+		bh = ufs_getfrag (inode, block, 1, &err);
+		if (!bh) {
+			if (!written)
+				written = err;
+			break;
+		}
+		if (c > count)
+			c = count;
+		if (c != sb->s_blocksize && !buffer_uptodate(bh)) {
+			ll_rw_block (READ, 1, &bh);
+			wait_on_buffer (bh);
+			if (!buffer_uptodate(bh)) {
+				brelse (bh);
+				if (!written)
+					written = -EIO;
+				break;
+			}
+		}
+		c -= copy_from_user (bh->b_data + offset, buf, c);
+		if (!c) {
+			brelse(bh);
+			if (!written)
+				written = -EFAULT;
+			break;
+		}
+		update_vm_cache(inode, pos, bh->b_data + offset, c);
+		pos += c;
+		written += c;
+		buf += c;
+		count -= c;
+		mark_buffer_uptodate(bh, 1);
+		mark_buffer_dirty(bh, 0);
+		if (filp->f_flags & O_SYNC)
+			bufferlist[buffercount++] = bh;
+		else
+			brelse(bh);
+		if (buffercount == NBUF){
+			ll_rw_block(WRITE, buffercount, bufferlist);
+			for(i=0; i<buffercount; i++){
+				wait_on_buffer(bufferlist[i]);
+				if (!buffer_uptodate(bufferlist[i]))
+					write_error=1;
+				brelse(bufferlist[i]);
+			}
+			buffercount=0;
+		}
+		if (write_error)
+			break;
+		block++;
+		offset = 0;
+		c = sb->s_blocksize;
+	} while (count);
+	if (buffercount){
+		ll_rw_block(WRITE, buffercount, bufferlist);
+		for (i=0; i<buffercount; i++){
+			wait_on_buffer(bufferlist[i]);
+			if (!buffer_uptodate(bufferlist[i]))
+				write_error=1;
+			brelse(bufferlist[i]);
+		}
+	}		
+	if (pos > inode->i_size)
+		inode->i_size = pos;
+	if (filp->f_flags & O_SYNC)
+		inode->u.ufs_i.i_osync--;
+	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+	*ppos = pos;
+	mark_inode_dirty(inode);
+	return written;
+}
+
+/*
+ * Called when an inode is released. Note that this is different
+ * from ufs_open: open gets called at every open, but release
+ * gets called only when /all/ the files are closed.
+ */
+static int ufs_release_file (struct inode * inode, struct file * filp)
+{
+	return 0;
+}
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ialloc.c linux/fs/ufs/ialloc.c
--- v2.1.111/linux/fs/ufs/ialloc.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/ufs/ialloc.c	Sun Jul 26 01:20:22 1998
@@ -0,0 +1,341 @@
+/*
+ *  linux/fs/ufs/ialloc.c
+ *
+ * Copyright (c) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ *
+ *  from
+ *
+ *  linux/fs/ext2/ialloc.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  BSD ufs-inspired inode and directory allocation by 
+ *  Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
+#include <asm/bitops.h>
+#include <asm/byteorder.h>
+
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_IALLOC_DEBUG
+#undef UFS_IALLOC_DEBUG_MORE
+
+#ifdef UFS_IALLOC_DEBUG
+#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+#ifdef UFS_IALLOC_DEBUG_MORE
+#define UFSDM \
+ufs_print_cylinder_stuff (ucg, swab); \
+printk("inode: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nifree), SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nifree), SWAB32(ucg->cg_cs.cs_nifree)); \
+printk("block: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nbfree), SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nbfree), SWAB32(ucg->cg_cs.cs_nbfree)); \
+printk("fragment: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_nffree), SWAB32(sb->fs_cs(ucpi->c_cgx).cs_nffree), SWAB32(ucg->cg_cs.cs_nffree)); \
+printk("ndir: total %u, fs %u, cg %u\n", SWAB32(usb1->fs_cstotal.cs_ndir), SWAB32(sb->fs_cs(ucpi->c_cgx).cs_ndir), SWAB32(ucg->cg_cs.cs_ndir));
+#else
+#define UFSDM
+#endif
+
+
+/*
+ * NOTE! When we get the inode, we're the only people
+ * that have access to it, and as such there are no
+ * race conditions we have to worry about. The inode
+ * is not on the hash-lists, and it cannot be reached
+ * through the filesystem because the directory entry
+ * has been deleted earlier.
+ *
+ * HOWEVER: we must make sure that we get no aliases,
+ * which means that we have to call "clear_inode()"
+ * _before_ we mark the inode not in use in the inode
+ * bitmaps. Otherwise a newly created file might use
+ * the same inode number (not actually the same pointer
+ * though), and then we'd have two inodes sharing the
+ * same inode number and space on the harddisk.
+ */
+void ufs_free_inode (struct inode * inode)
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block_first * usb1;
+	struct ufs_cg_private_info * ucpi;
+	struct ufs_cylinder_group * ucg;
+	int is_directory;
+	unsigned ino, cg, bit;
+	unsigned swab;
+	
+	UFSD(("ENTER, ino %lu\n", inode->i_ino))
+
+	if (!inode)
+		return;
+	sb = inode->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+	usb1 = ubh_get_usb_first(USPI_UBH);
+	
+	if (inode->i_count > 1) {
+		ufs_warning(sb, "ufs_free_inode", "inode has count=%d\n", inode->i_count);
+		return;
+	}
+	if (inode->i_nlink) {
+		ufs_warning(sb, "ufs_free_inode", "inode has nlink=%d\n", inode->i_nlink);
+		return;
+	}
+
+	ino = inode->i_ino;
+
+	lock_super (sb);
+
+	if (!((ino > 1) && (ino < (uspi->s_ncg * uspi->s_ipg )))) {
+		ufs_warning(sb, "ufs_free_inode", "reserved inode or nonexistent inode %u\n", ino);
+		unlock_super (sb);
+		return;
+	}
+	
+	cg = ufs_inotocg (ino);
+	bit = ufs_inotocgoff (ino);
+	ucpi = ufs_load_cylinder (sb, cg);
+	if (!ucpi) {
+		unlock_super (sb);
+		return;
+	}
+	ucg = ubh_get_ucg(UCPI_UBH);
+	if (!ufs_cg_chkmagic(ucg))
+		ufs_panic (sb, "ufs_free_fragments", "internal error, bad cg magic number");
+
+	UFSDM
+	
+	ucg->cg_time = SWAB32(CURRENT_TIME);
+
+	is_directory = S_ISDIR(inode->i_mode);
+
+	DQUOT_FREE_INODE(sb, inode);
+
+	clear_inode (inode);
+
+	if (ubh_isclr (UCPI_UBH, ucpi->c_iusedoff, bit))
+		ufs_error(sb, "ufs_free_inode", "bit already cleared for inode %u", ino);
+	else {
+		ubh_clrbit (UCPI_UBH, ucpi->c_iusedoff, bit);
+		if (ino < ucpi->c_irotor)
+			ucpi->c_irotor = ino;
+		INC_SWAB32(ucg->cg_cs.cs_nifree);
+		INC_SWAB32(usb1->fs_cstotal.cs_nifree);
+		INC_SWAB32(sb->fs_cs(cg).cs_nifree);
+
+		if (is_directory) {
+			DEC_SWAB32(ucg->cg_cs.cs_ndir);
+			DEC_SWAB32(usb1->fs_cstotal.cs_ndir);
+			DEC_SWAB32(sb->fs_cs(cg).cs_ndir);
+		}
+	}
+	ubh_mark_buffer_dirty (USPI_UBH, 1);
+	ubh_mark_buffer_dirty (UCPI_UBH, 1);
+	if (sb->s_flags & MS_SYNCHRONOUS) {
+		ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **) &ucpi);
+		ubh_wait_on_buffer (UCPI_UBH);
+	}
+	
+	UFSDM
+	
+	sb->s_dirt = 1;
+	unlock_super (sb);
+	UFSD(("EXIT\n"))
+}
+
+/*
+ * There are two policies for allocating an inode.  If the new inode is
+ * a directory, then a forward search is made for a block group with both
+ * free space and a low directory-to-inode ratio; if that fails, then of
+ * the groups with above-average free space, that group with the fewest
+ * directories already is chosen.
+ *
+ * For other inodes, search forward from the parent directory\'s block
+ * group to find a free inode.
+ */
+struct inode * ufs_new_inode (const struct inode * dir,	int mode, int * err )
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block_first * usb1;
+	struct ufs_cg_private_info * ucpi;
+	struct ufs_cylinder_group * ucg;
+	struct inode * inode;
+	unsigned cg, bit, i, j, start;
+	unsigned swab;
+
+	UFSD(("ENTER\n"))
+	
+	/* Cannot create files in a deleted directory */
+	if (!dir || !dir->i_nlink) {
+		*err = -EPERM;
+		return NULL;
+	}
+	inode = get_empty_inode ();
+	if (!inode) {
+		*err = -ENOMEM;
+		return NULL;
+	}
+	sb = dir->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+	usb1 = ubh_get_usb_first(USPI_UBH);
+
+	inode->i_sb = sb;
+	inode->i_flags = sb->s_flags;
+	
+	lock_super (sb);
+
+	*err = -ENOSPC;
+
+	/*
+	 * Try to place the inode in its parent directory
+	 */
+	i = ufs_inotocg(dir->i_ino);
+	if (SWAB32(sb->fs_cs(i).cs_nifree)) {
+		cg = i;
+		goto cg_found;
+	}
+
+	/*
+	 * Use a quadratic hash to find a group with a free inode
+	 */
+	for ( j = 1; j < uspi->s_ncg; j <<= 1 ) {
+		i += j;
+		if (i >= uspi->s_ncg)
+			i -= uspi->s_ncg;
+		if (SWAB32(sb->fs_cs(i).cs_nifree)) {
+			cg = i;
+			goto cg_found;
+		}
+	}
+
+	/*
+	 * That failed: try linear search for a free inode
+	 */
+	i = ufs_inotocg(dir->i_ino) + 1;
+	for (j = 2; j < uspi->s_ncg; j++) {
+		i++;
+		if (i >= uspi->s_ncg)
+			i = 0;
+		if (SWAB32(sb->fs_cs(i).cs_nifree)) {
+			cg = i;
+			goto cg_found;
+		}
+	}
+	
+	goto failed;
+
+cg_found:
+	ucpi = ufs_load_cylinder (sb, cg);
+	if (!ucpi)
+		goto failed;
+	ucg = ubh_get_ucg(UCPI_UBH);
+	if (!ufs_cg_chkmagic(ucg)) 
+		ufs_panic (sb, "ufs_new_inode", "internal error, bad cg magic number");
+
+	UFSDM
+	
+	start = ucpi->c_irotor;
+	bit = ubh_find_next_zero_bit (UCPI_UBH, ucpi->c_iusedoff, uspi->s_ipg, start);
+	if (!(bit < uspi->s_ipg)) {
+		bit = ubh_find_first_zero_bit (UCPI_UBH, ucpi->c_iusedoff, start);
+		if (!(bit < start)) {
+			ufs_error (sb, "ufs_new_inode",
+			    "cylinder group %u corrupted - error in inode bitmap\n", cg);
+			goto failed;
+		}
+	}
+	UFSD(("start = %u, bit = %u, ipg = %u\n", start, bit, uspi->s_ipg))
+	if (ubh_isclr (UCPI_UBH, ucpi->c_iusedoff, bit))
+		ubh_setbit (UCPI_UBH, ucpi->c_iusedoff, bit);
+	else {
+		ufs_panic (sb, "ufs_new_inode", "internal error");
+		goto failed;
+	}
+	
+	DEC_SWAB32(ucg->cg_cs.cs_nifree);
+	DEC_SWAB32(usb1->fs_cstotal.cs_nifree);
+	DEC_SWAB32(sb->fs_cs(cg).cs_nifree);
+	
+	if (S_ISDIR(mode)) {
+		INC_SWAB32(ucg->cg_cs.cs_ndir);
+		INC_SWAB32(usb1->fs_cstotal.cs_ndir);
+		INC_SWAB32(sb->fs_cs(cg).cs_ndir);
+	}
+
+	ubh_mark_buffer_dirty (USPI_UBH, 1);
+	ubh_mark_buffer_dirty (UCPI_UBH, 1);
+	if (sb->s_flags & MS_SYNCHRONOUS) {
+		ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **) &ucpi);
+		ubh_wait_on_buffer (UCPI_UBH);
+	}
+	sb->s_dirt = 1;
+
+	inode->i_mode = mode;
+	inode->i_sb = sb;
+	inode->i_nlink = 1;
+	inode->i_dev = sb->s_dev;
+	inode->i_uid = current->fsuid;
+	if (test_opt (sb, GRPID))
+		inode->i_gid = dir->i_gid;
+	else if (dir->i_mode & S_ISGID) {
+		inode->i_gid = dir->i_gid;
+		if (S_ISDIR(mode))
+			mode |= S_ISGID;
+	} else
+		inode->i_gid = current->fsgid;
+
+	inode->i_ino = cg * uspi->s_ipg + bit;
+	inode->i_blksize = PAGE_SIZE;	/* This is the optimal IO size (for stat), not the fs block size */
+	inode->i_blocks = 0;
+	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+	inode->u.ufs_i.i_flags = dir->u.ufs_i.i_flags;
+	inode->u.ufs_i.i_uid = inode->i_uid;
+	inode->u.ufs_i.i_gid = inode->i_gid;
+	inode->u.ufs_i.i_lastfrag = 0;
+	inode->i_op = NULL;
+
+	insert_inode_hash(inode);
+	mark_inode_dirty(inode);
+
+	UFSDM
+	
+	unlock_super (sb);
+
+	if(DQUOT_ALLOC_INODE(sb, inode)) {
+		sb->dq_op->drop(inode);
+		inode->i_nlink = 0;
+		iput(inode);
+		*err = -EDQUOT;
+		return NULL;
+	}
+
+	UFSD(("allocating inode %lu\n", inode->i_ino))
+	*err = 0;
+	UFSD(("EXIT\n"))
+	return inode;
+
+failed:
+	unlock_super (sb);
+	iput (inode);
+	UFSD(("EXIT (FAILED)\n"))
+	return NULL;
+}
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/inode.c linux/fs/ufs/inode.c
--- v2.1.111/linux/fs/ufs/inode.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/ufs/inode.c	Sun Jul 26 01:20:22 1998
@@ -0,0 +1,665 @@
+/*
+ *  linux/ufs/ufs/inode.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ *
+ *  from
+ *
+ *  linux/fs/ext2/inode.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/fs/minix/inode.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/mm.h>
+
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_INODE_DEBUG
+#undef UFS_INODE_DEBUG_MORE
+
+#ifdef UFS_INODE_DEBUG
+#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+#ifdef UFS_INODE_DEBUG_MORE
+static void ufs_print_inode(struct inode * inode)
+{
+	unsigned swab = inode->i_sb->u.ufs_sb.s_swab;
+	printk("ino %lu  mode 0%6.6o  nlink %d  uid %d  gid %d"
+	       "  size %lu blocks %lu\n",
+	       inode->i_ino, inode->i_mode, inode->i_nlink,
+	       inode->i_uid,inode->i_gid, inode->i_size, inode->i_blocks);
+	printk("  db <%u %u %u %u %u %u %u %u %u %u %u %u>\n",
+		SWAB32(inode->u.ufs_i.i_u1.i_data[0]),
+		SWAB32(inode->u.ufs_i.i_u1.i_data[1]),
+		SWAB32(inode->u.ufs_i.i_u1.i_data[2]),
+		SWAB32(inode->u.ufs_i.i_u1.i_data[3]),
+		SWAB32(inode->u.ufs_i.i_u1.i_data[4]),
+		SWAB32(inode->u.ufs_i.i_u1.i_data[5]),
+		SWAB32(inode->u.ufs_i.i_u1.i_data[6]),
+		SWAB32(inode->u.ufs_i.i_u1.i_data[7]),
+		SWAB32(inode->u.ufs_i.i_u1.i_data[8]),
+		SWAB32(inode->u.ufs_i.i_u1.i_data[9]),
+		SWAB32(inode->u.ufs_i.i_u1.i_data[10]),
+		SWAB32(inode->u.ufs_i.i_u1.i_data[11]));
+	printk("  gen %u ib <%u %u %u>\n",
+		inode->u.ufs_i.i_gen,
+		SWAB32(inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK]),
+		SWAB32(inode->u.ufs_i.i_u1.i_data[UFS_DIND_BLOCK]),
+		SWAB32(inode->u.ufs_i.i_u1.i_data[UFS_TIND_BLOCK]));
+}
+#endif
+
+#define ufs_inode_bmap(inode, nr) \
+	(SWAB32((inode)->u.ufs_i.i_u1.i_data[(nr) >> uspi->s_fpbshift]) + ((nr) & uspi->s_fpbmask))
+
+static inline unsigned ufs_block_bmap (struct buffer_head * bh, unsigned nr, 
+	struct ufs_sb_private_info * uspi, unsigned swab)
+{
+	unsigned tmp;
+
+	UFSD(("ENTER, nr %u\n", nr))
+	if (!bh)
+		return 0;
+	tmp = SWAB32(((u32 *) bh->b_data)[nr >> uspi->s_fpbshift]) + (nr & uspi->s_fpbmask);
+	brelse (bh);
+	UFSD(("EXIT, resutl %u\n", tmp))
+	return tmp;
+}
+
+int ufs_bmap (struct inode * inode, int fragment)
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	unsigned tmp;
+	unsigned swab;
+	
+	sb = inode->i_sb;
+	uspi = sb->u.ufs_sb.s_uspi;
+	swab = sb->u.ufs_sb.s_swab;
+
+	UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
+	
+	if (fragment >= ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) << uspi->s_fpbshift)) {
+		ufs_warning (sb, "ufs_bmap", "block > big");
+		return 0;
+	}
+
+	/*
+	 * direct fragment
+	 */
+	if (fragment < UFS_NDIR_FRAGMENT)
+		return ufs_inode_bmap (inode, fragment);
+
+	/*
+	 * indirect fragment
+	 */	
+	fragment -= UFS_NDIR_FRAGMENT;
+	if (fragment < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
+		tmp = ufs_inode_bmap (inode, 
+			UFS_IND_FRAGMENT + (fragment >> uspi->s_apbshift));
+		if (!tmp)
+			return 0;
+		return ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize), 
+			fragment & uspi->s_apbmask, uspi, swab);
+	}
+
+	/*
+	 * dindirect fragment
+	 */
+	fragment -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
+	if (fragment < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
+		tmp = ufs_inode_bmap (inode,
+			UFS_DIND_FRAGMENT + (fragment >> uspi->s_2apbshift));
+		if (!tmp)
+			return 0;
+		tmp = ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
+			(fragment >> uspi->s_apbshift) & uspi->s_apbmask, uspi, swab);
+		if (!tmp)
+			return 0;
+		return ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
+			fragment & uspi->s_apbmask, uspi, swab);
+	}
+
+	/*
+	 * tindirect fragment
+	 */
+	fragment -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
+	tmp = ufs_inode_bmap (inode, 
+		UFS_TIND_FRAGMENT + (fragment >> uspi->s_3apbshift));
+	if (!tmp)
+		return 0;
+	tmp = ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
+		(fragment >> uspi->s_2apbshift) & uspi->s_apbmask, uspi, swab);
+	if (!tmp)
+		return 0;
+	tmp = ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
+		(fragment >> uspi->s_apbshift) & uspi->s_apbmask, uspi, swab);
+	if (!tmp)
+		return 0;
+	return ufs_block_bmap (bread (sb->s_dev, tmp, sb->s_blocksize),
+		fragment & uspi->s_apbmask, uspi, swab);
+}
+
+static struct buffer_head * ufs_inode_getfrag (struct inode * inode, 
+	unsigned fragment, unsigned new_fragment, int create, 
+	unsigned required, int * err )
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct buffer_head * result;
+	unsigned long limit;
+	unsigned block, blockoff, lastfrag, lastblock, lastblockoff;
+	unsigned tmp, goal;
+	u32 * p, * p2;
+	unsigned swab;
+
+	UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u, required %u\n",
+		inode->i_ino, fragment, new_fragment, required))         
+
+	sb = inode->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+	block = ufs_fragstoblks (fragment);
+	blockoff = ufs_fragnum (fragment);
+	p = inode->u.ufs_i.i_u1.i_data + block;
+	goal = 0;
+
+repeat:
+	tmp = SWAB32(*p);
+	lastfrag = inode->u.ufs_i.i_lastfrag;
+	if (tmp && fragment < lastfrag) {
+		result = getblk (sb->s_dev, tmp + blockoff, sb->s_blocksize);
+		if (tmp == SWAB32(*p)) {
+			UFSD(("EXIT, result %u\n", tmp + blockoff))
+			return result;
+		}
+		brelse (result);
+		goto repeat;
+	}
+	*err = -EFBIG;
+	if (!create)
+		return NULL;
+	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+	if (limit < RLIM_INFINITY) {
+		limit >>= sb->s_blocksize_bits;
+		if (new_fragment >= limit) {
+			send_sig(SIGXFSZ, current, 0);
+			return NULL;
+		}
+	}
+	lastblock = ufs_fragstoblks (lastfrag);
+	lastblockoff = ufs_fragnum (lastfrag);
+	/*
+	 * We will extend file into new block beyond last allocated block
+	 */
+	if (lastblock < block) {
+		/*
+		 * We must reallocate last allocated block
+		 */
+		if (lastblockoff) {
+			p2 = inode->u.ufs_i.i_u1.i_data + lastblock;
+			tmp = ufs_new_fragments (inode, p2, lastfrag, 
+				SWAB32(*p2), uspi->s_fpb - lastblockoff, err);
+			if (!tmp) {
+				if (lastfrag != inode->u.ufs_i.i_lastfrag)
+					goto repeat;
+				else
+					return NULL;
+			}
+			lastfrag = inode->u.ufs_i.i_lastfrag;
+			
+		}
+		goal = SWAB32(inode->u.ufs_i.i_u1.i_data[lastblock]) + uspi->s_fpb;
+		tmp = ufs_new_fragments (inode, p, fragment - blockoff, 
+			goal, required + blockoff, err);
+	}
+	/*
+	 * We will extend last allocated block
+	 */
+	else if (lastblock == block) {
+		tmp = ufs_new_fragments (inode, p, fragment - (blockoff - lastblockoff),
+			SWAB32(*p), required +  (blockoff - lastblockoff), err);
+	}
+	/*
+	 * We will allocated new block before last allocat block
+	 */
+	else /* (lastblock > block) */ {
+		if (lastblock && (tmp = SWAB32(inode->u.ufs_i.i_u1.i_data[lastblock-1])))
+ 			goal = tmp + uspi->s_fpb;
+		tmp = ufs_new_fragments (inode, p, fragment - blockoff, 
+			goal, uspi->s_fpb, err);
+	}
+	if (!tmp) {
+		if ((!blockoff && SWAB32(*p)) || 
+		(blockoff && lastfrag != inode->u.ufs_i.i_lastfrag))
+			goto repeat;
+		else
+			return NULL;
+	}
+	result = getblk (inode->i_dev, tmp + blockoff, sb->s_blocksize);
+	inode->i_ctime = CURRENT_TIME;
+	if (IS_SYNC(inode))
+		ufs_sync_inode (inode);
+	mark_inode_dirty(inode);
+	UFSD(("EXIT, result %u\n", tmp + blockoff))
+	return result;
+}
+
+static struct buffer_head * ufs_block_getfrag (struct inode * inode,
+	struct buffer_head * bh, unsigned fragment, unsigned new_fragment, 
+	int create, unsigned blocksize, int * err)
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct buffer_head * result;
+	unsigned tmp, goal, block, blockoff;
+	u32 * p;
+	unsigned swab;
+
+	sb = inode->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+	block = ufs_fragstoblks (fragment);
+	blockoff = ufs_fragnum (fragment);
+
+	UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u\n", inode->i_ino, fragment, new_fragment))	
+
+	if (!bh)
+		return NULL;
+	if (!buffer_uptodate(bh)) {
+		ll_rw_block (READ, 1, &bh);
+		wait_on_buffer (bh);
+		if (!buffer_uptodate(bh)) {
+			brelse (bh);
+			return NULL;
+		}
+	}
+
+	p = (u32 *) bh->b_data + block;
+repeat:
+	tmp = SWAB32(*p);
+	if (tmp) {
+		result = getblk (bh->b_dev, tmp + blockoff, sb->s_blocksize);
+		if (tmp == SWAB32(*p)) {
+			brelse (bh);
+			UFSD(("EXIT, result %u\n", tmp + blockoff))
+			return result;
+		}
+		brelse (result);
+		goto repeat;
+	}
+	if (!create || new_fragment >= (current->rlim[RLIMIT_FSIZE].rlim_cur >> sb->s_blocksize)) {
+		brelse (bh);
+		*err = -EFBIG;
+		return NULL;
+	}
+ 	if (block && (tmp = SWAB32(((u32*)bh->b_data)[block-1]) + uspi->s_fpb))
+ 		goal = tmp + uspi->s_fpb;
+ 	else
+ 		goal = bh->b_blocknr + uspi->s_fpb;
+	tmp = ufs_new_fragments (inode, p, ufs_blknum(new_fragment), goal, uspi->s_fpb, err);
+	if (!tmp) {
+		if (SWAB32(*p)) {
+			printk("REPEAT\n");
+			goto repeat;
+		}
+		else {
+			return NULL;
+		}
+	}		
+	result = getblk (bh->b_dev, tmp + blockoff, sb->s_blocksize);
+	mark_buffer_dirty(bh, 1);
+	if (IS_SYNC(inode)) {
+		ll_rw_block (WRITE, 1, &bh);
+		wait_on_buffer (bh);
+	}
+	inode->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(inode);
+	brelse (bh);
+	UFSD(("EXIT, resutl %u\n", tmp + blockoff))
+	return result;
+}
+
+struct buffer_head * ufs_getfrag (struct inode * inode, unsigned fragment,
+	int create, int * err)
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct buffer_head * bh;
+	unsigned f;
+	unsigned swab;
+	
+	sb = inode->i_sb;
+	uspi = sb->u.ufs_sb.s_uspi;
+	swab = sb->u.ufs_sb.s_swab;
+	*err = -EIO;
+
+	UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
+	if (fragment > ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) << uspi->s_fpbshift)) {
+		ufs_warning (sb, "ufs_getblk", "block > big");
+		return NULL;
+	}
+
+	*err = -ENOSPC;
+	f = fragment;
+	  
+	/*
+	 * Direct fragment
+	 */
+	if (fragment < UFS_NDIR_FRAGMENT)
+		return ufs_inode_getfrag (inode, fragment, fragment, create, 1, err);
+	/*
+	 * Indirect fragment
+	 */
+	fragment -= UFS_NDIR_FRAGMENT;
+	if (fragment < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
+		bh = ufs_inode_getfrag (inode, 
+			UFS_IND_FRAGMENT + (fragment >> uspi->s_apbshift),
+			f, create, uspi->s_fpb, err);
+		return ufs_block_getfrag (inode, bh, 
+			fragment & uspi->s_apbmask,
+			f, create, sb->s_blocksize, err);
+	}
+	/*
+	 * Dindirect fragment
+	 */
+	fragment -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
+	if ( fragment < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
+		bh = ufs_inode_getfrag (inode,
+			UFS_DIND_FRAGMENT + (fragment >> uspi->s_2apbshift), 
+			f, create, uspi->s_fpb, err);
+		bh = ufs_block_getfrag (inode, bh,
+			(fragment >> uspi->s_apbshift) & uspi->s_apbmask, 
+			f, create, sb->s_blocksize, err);
+		return ufs_block_getfrag (inode, bh, 
+			fragment & uspi->s_apbmask,
+			f, create, sb->s_blocksize, err);
+	}
+	/*
+	 * Tindirect fragment
+	 */
+	fragment -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
+	bh = ufs_inode_getfrag (inode,
+		UFS_TIND_FRAGMENT + (fragment >> uspi->s_3apbshift), 
+		f, create, uspi->s_fpb, err);
+	bh = ufs_block_getfrag (inode, bh,
+		(fragment >> uspi->s_2apbshift) & uspi->s_apbmask,
+		f, create, sb->s_blocksize, err);
+	bh = ufs_block_getfrag (inode, bh,
+		(fragment >> uspi->s_apbshift) & uspi->s_apbmask, 
+		f, create, sb->s_blocksize, err);
+	return ufs_block_getfrag (inode, bh,
+		fragment & uspi->s_apbmask, 
+		f, create, sb->s_blocksize, err);
+}
+
+
+
+struct buffer_head * ufs_bread (struct inode * inode, unsigned fragment,
+	int create, int * err)
+{
+	struct buffer_head * bh;
+
+	UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
+	bh = ufs_getfrag (inode, fragment, create, err);
+	if (!bh || buffer_uptodate(bh)) 		
+		return bh;
+	ll_rw_block (READ, 1, &bh);
+	wait_on_buffer (bh);
+	if (buffer_uptodate(bh))
+		return bh;
+	brelse (bh);
+	*err = -EIO;
+	return NULL;
+}
+
+void ufs_read_inode (struct inode * inode)
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct ufs_inode * ufs_inode;	
+	struct buffer_head * bh;
+	unsigned i;
+	unsigned flags, swab;
+	
+	UFSD(("ENTER, ino %lu\n", inode->i_ino))
+	
+	sb = inode->i_sb;
+	uspi = sb->u.ufs_sb.s_uspi;
+	flags = sb->u.ufs_sb.s_flags;
+	swab = sb->u.ufs_sb.s_swab;
+
+	if (inode->i_ino < UFS_ROOTINO || 
+	    inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) {
+		ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino);
+		return;
+	}
+	
+	bh = bread (sb->s_dev, ufs_inotofsba(inode->i_ino), sb->s_blocksize);
+	if (!bh) {
+		ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino);
+		return;
+	}
+	ufs_inode = (struct ufs_inode *) (bh->b_data + sizeof(struct ufs_inode) * ufs_inotofsbo(inode->i_ino));
+
+	/*
+	 * Copy data to the in-core inode.
+	 */
+	inode->i_mode = SWAB16(ufs_inode->ui_mode);
+	inode->i_nlink = SWAB16(ufs_inode->ui_nlink);
+	if (inode->i_nlink == 0)
+		ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino);
+	
+	/*
+	 * Linux has only 16-bit uid and gid, so we can't support EFT.
+	 * Files are dynamically chown()ed to root.
+	 */
+	inode->i_uid = ufs_uid(ufs_inode);
+	if (inode->i_uid == UFS_USEEFT) {
+		inode->i_uid = 0;
+	}
+	if (inode->i_gid == UFS_USEEFT) {
+		inode->i_gid = 0;
+	}
+	
+	/*
+	 * Linux i_size can be 32 on some architektures. We will mark 
+	 * big files as read only and let user access first 32 bits.
+	 */
+	inode->u.ufs_i.i_size = SWAB64(ufs_inode->ui_size);
+	inode->i_size = (off_t) inode->u.ufs_i.i_size;
+	if (sizeof(off_t) == 4 && (inode->u.ufs_i.i_size >> 32))
+		inode->i_size = (__u32)-1;
+
+	inode->i_atime = SWAB32(ufs_inode->ui_atime.tv_sec);
+	inode->i_ctime = SWAB32(ufs_inode->ui_ctime.tv_sec);
+	inode->i_mtime = SWAB32(ufs_inode->ui_mtime.tv_sec);
+	inode->i_blocks = SWAB32(ufs_inode->ui_blocks);
+	inode->i_blksize = PAGE_SIZE;   /* This is the optimal IO size (for stat) */
+	inode->i_version = ++event;
+
+	inode->u.ufs_i.i_flags = SWAB32(ufs_inode->ui_flags);
+	inode->u.ufs_i.i_gen = SWAB32(ufs_inode->ui_gen);
+	inode->u.ufs_i.i_shadow = SWAB32(ufs_inode->ui_u3.ui_sun.ui_shadow);
+	inode->u.ufs_i.i_uid = SWAB32(ufs_inode->ui_u3.ui_sun.ui_uid);
+	inode->u.ufs_i.i_gid = SWAB32(ufs_inode->ui_u3.ui_sun.ui_gid);
+	inode->u.ufs_i.i_oeftflag = SWAB32(ufs_inode->ui_u3.ui_sun.ui_oeftflag);
+	inode->u.ufs_i.i_lastfrag = howmany (inode->i_size, uspi->s_fsize);
+	
+	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+		inode->i_rdev = to_kdev_t(SWAB32(ufs_inode->ui_u2.ui_addr.ui_db[0]));
+	else if (inode->i_blocks) {
+		for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
+			inode->u.ufs_i.i_u1.i_data[i] = ufs_inode->ui_u2.ui_addr.ui_db[i];
+	}
+	else {
+		for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
+			inode->u.ufs_i.i_u1.i_symlink[i] = ufs_inode->ui_u2.ui_symlink[i];
+	}
+
+	brelse (bh);
+
+	inode->i_op = NULL;
+
+	if (S_ISREG(inode->i_mode))
+		inode->i_op = &ufs_file_inode_operations;
+	else if (S_ISDIR(inode->i_mode))
+		inode->i_op = &ufs_dir_inode_operations;
+	else if (S_ISLNK(inode->i_mode))
+		inode->i_op = &ufs_symlink_inode_operations;
+	else if (S_ISCHR(inode->i_mode))
+		inode->i_op = &chrdev_inode_operations;
+	else if (S_ISBLK(inode->i_mode))
+		inode->i_op = &blkdev_inode_operations;
+	else if (S_ISSOCK(inode->i_mode))
+		; /* nothing */
+	else if (S_ISFIFO(inode->i_mode))
+		init_fifo(inode);
+
+#ifdef UFS_INODE_DEBUG_MORE
+	ufs_print_inode (inode);
+#endif
+	UFSD(("EXIT\n"))
+}
+
+static int ufs_update_inode(struct inode * inode, int do_sync)
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct buffer_head * bh;
+	struct ufs_inode * ufs_inode;
+	unsigned i;
+	unsigned swab;
+
+	UFSD(("ENTER, ino %lu\n", inode->i_ino))
+
+	sb = inode->i_sb;
+	uspi = sb->u.ufs_sb.s_uspi;
+	swab = sb->u.ufs_sb.s_swab;
+
+	if (inode->i_ino < UFS_ROOTINO || 
+	    inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) {
+		ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino);
+		return -1;
+	}
+
+	bh = bread (sb->s_dev, ufs_inotofsba(inode->i_ino), sb->s_blocksize);
+	if (!bh) {
+		ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino);
+		return -1;
+	}
+	ufs_inode = (struct ufs_inode *) (bh->b_data + ufs_inotofsbo(inode->i_ino) * sizeof(struct ufs_inode));
+
+	ufs_inode->ui_mode = SWAB16(inode->i_mode);
+	ufs_inode->ui_nlink = SWAB16(inode->i_nlink);
+
+	if (inode->i_uid == 0 && inode->u.ufs_i.i_uid >= UFS_USEEFT) {
+		ufs_inode->ui_u3.ui_sun.ui_uid = SWAB32(inode->u.ufs_i.i_uid);
+		ufs_inode->ui_u1.oldids.ui_suid = (__u16)ufs_inode->ui_u3.ui_sun.ui_uid;
+	}
+	else {
+		ufs_inode->ui_u1.oldids.ui_suid = SWAB16(inode->i_uid);
+		ufs_inode->ui_u3.ui_sun.ui_uid = (__u32) ufs_inode->ui_u1.oldids.ui_suid;
+	}
+	if (inode->i_gid == 0 && inode->u.ufs_i.i_gid >= UFS_USEEFT) {
+		ufs_inode->ui_u3.ui_sun.ui_gid = SWAB32(inode->u.ufs_i.i_gid);
+		ufs_inode->ui_u1.oldids.ui_sgid = (__u16)ufs_inode->ui_u3.ui_sun.ui_gid;
+	}
+	else {
+		ufs_inode->ui_u1.oldids.ui_sgid = SWAB16(inode->i_gid);
+		ufs_inode->ui_u3.ui_sun.ui_gid = (__u32) ufs_inode->ui_u1.oldids.ui_sgid;
+	}
+		
+	ufs_inode->ui_size = SWAB64((u64)inode->i_size);
+	ufs_inode->ui_atime.tv_sec = SWAB32(inode->i_atime);
+	ufs_inode->ui_atime.tv_usec = SWAB32(0);
+	ufs_inode->ui_ctime.tv_sec = SWAB32(inode->i_ctime);
+	ufs_inode->ui_ctime.tv_usec = SWAB32(0);
+	ufs_inode->ui_mtime.tv_sec = SWAB32(inode->i_mtime);
+	ufs_inode->ui_mtime.tv_usec = SWAB32(0);
+	ufs_inode->ui_blocks = SWAB32(inode->i_blocks);
+
+	ufs_inode->ui_flags = SWAB32(inode->u.ufs_i.i_flags);
+	ufs_inode->ui_gen = SWAB32(inode->u.ufs_i.i_gen);
+	ufs_inode->ui_u3.ui_sun.ui_shadow = SWAB32(inode->u.ufs_i.i_shadow);
+	ufs_inode->ui_u3.ui_sun.ui_oeftflag = SWAB32(inode->u.ufs_i.i_oeftflag);
+
+	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+		ufs_inode->ui_u2.ui_addr.ui_db[0] = SWAB32(kdev_t_to_nr(inode->i_rdev));
+	else if (inode->i_blocks) {
+		for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
+			ufs_inode->ui_u2.ui_addr.ui_db[i] = inode->u.ufs_i.i_u1.i_data[i];
+	}
+	else {
+		for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
+			ufs_inode->ui_u2.ui_symlink[i] = inode->u.ufs_i.i_u1.i_symlink[i];
+	}
+
+	if (!inode->i_nlink)
+		memset (ufs_inode, 0, sizeof(struct ufs_inode));
+		
+	mark_buffer_dirty(bh, 1);
+	if (do_sync) {
+		ll_rw_block (WRITE, 1, &bh);
+		wait_on_buffer (bh);
+	}
+	brelse (bh);
+	
+	UFSD(("EXIT\n"))
+	return 0;
+}
+
+void ufs_write_inode (struct inode * inode)
+{
+	ufs_update_inode (inode, 0);
+}
+
+int ufs_sync_inode (struct inode *inode)
+{
+	return ufs_update_inode (inode, 1);
+}
+
+void ufs_put_inode (struct inode * inode)
+{
+	UFSD(("ENTER & EXIT\n"))
+}
+
+void ufs_delete_inode (struct inode * inode)
+{
+	/*inode->u.ufs_i.i_dtime = CURRENT_TIME;*/
+	mark_inode_dirty(inode);
+	ufs_update_inode(inode, IS_SYNC(inode));
+	inode->i_size = 0;
+	if (inode->i_blocks)
+		ufs_truncate (inode);
+	ufs_free_inode (inode);
+}
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/namei.c linux/fs/ufs/namei.c
--- v2.1.111/linux/fs/ufs/namei.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/ufs/namei.c	Sun Jul 26 01:20:22 1998
@@ -0,0 +1,1147 @@
+/*
+ * linux/fs/ufs/namei.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ *
+ *  from
+ *
+ *  linux/fs/ext2/namei.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/fs/minix/namei.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+
+#include <asm/uaccess.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_NAMEI_DEBUG
+
+#ifdef UFS_NAMEI_DEBUG
+#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+/*
+ * define how far ahead to read directories while searching them.
+ */
+#define NAMEI_RA_CHUNKS  2
+#define NAMEI_RA_BLOCKS  4
+#define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
+#define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))
+
+/*
+ * NOTE! unlike strncmp, ufs_match returns 1 for success, 0 for failure.
+ */
+static int ufs_match (int len, const char * const name,
+	struct ufs_dir_entry * de, unsigned flags, unsigned swab)
+{
+	if (!de || !SWAB32(de->d_ino) || len > UFS_MAXNAMLEN)
+		return 0;
+	/*
+	 * "" means "." ---> so paths like "/usr/lib//libc.a" work
+	 */
+	if (!len && ufs_namlen(de) == 1 && (de->d_name[0] == '.') &&
+	   (de->d_name[1] == '\0'))
+		return 1;
+	if (len != ufs_namlen(de))
+		return 0;
+	return !memcmp(name, de->d_name, len);
+}
+
+/*
+ *	ufs_find_entry()
+ *
+ * finds an entry in the specified directory with the wanted name. It
+ * returns the cache buffer in which the entry was found, and the entry
+ * itself (as a parameter - res_dir). It does NOT read the inode of the
+ * entry - you'll have to do that yourself if you want to.
+ */
+static struct buffer_head * ufs_find_entry (struct inode * dir,
+	const char * const name, int namelen, struct ufs_dir_entry ** res_dir)
+{
+	struct super_block * sb;
+	struct buffer_head * bh_use[NAMEI_RA_SIZE];
+	struct buffer_head * bh_read[NAMEI_RA_SIZE];
+	unsigned long offset;
+	int block, toread, i, err;
+	unsigned flags, swab;
+
+	UFSD(("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen))
+	
+	*res_dir = NULL;
+	if (!dir) 
+		return NULL;
+	
+	sb = dir->i_sb;
+	flags = sb->u.ufs_sb.s_flags;
+	swab = sb->u.ufs_sb.s_swab;
+	
+	if (namelen > UFS_MAXNAMLEN)
+		return NULL;
+
+	memset (bh_use, 0, sizeof (bh_use));
+	toread = 0;
+	for (block = 0; block < NAMEI_RA_SIZE; ++block) {
+		struct buffer_head * bh;
+
+		if ((block << sb->s_blocksize_bits) >= dir->i_size)
+			break;
+		bh = ufs_getfrag (dir, block, 0, &err);
+		bh_use[block] = bh;
+		if (bh && !buffer_uptodate(bh))
+			bh_read[toread++] = bh;
+	}
+
+	for (block = 0, offset = 0; offset < dir->i_size; block++) {
+		struct buffer_head * bh;
+		struct ufs_dir_entry * de;
+		char * dlimit;
+
+		if ((block % NAMEI_RA_BLOCKS) == 0 && toread) {
+			ll_rw_block (READ, toread, bh_read);
+			toread = 0;
+		}
+		bh = bh_use[block % NAMEI_RA_SIZE];
+		if (!bh) {
+			ufs_error (sb, "ufs_find_entry",
+				"directory #%lu contains a hole at offset %lu", dir->i_ino, offset);
+			offset += sb->s_blocksize;
+			continue;
+		}
+		wait_on_buffer (bh);
+		if (!buffer_uptodate(bh)) {
+			/*
+			 * read error: all bets are off
+			 */
+			break;
+		}
+
+		de = (struct ufs_dir_entry *) bh->b_data;
+		dlimit = bh->b_data + sb->s_blocksize;
+		while ((char *) de < dlimit && offset < dir->i_size) {
+			if (!ufs_check_dir_entry ("ufs_find_entry", dir, de, bh, offset))
+				goto failed;
+			if (SWAB32(de->d_ino) != 0 && ufs_match (namelen, name, de, flags, swab)) {
+				for (i = 0; i < NAMEI_RA_SIZE; ++i) {
+					if (bh_use[i] != bh)
+						brelse (bh_use[i]);
+				}
+				*res_dir = de;
+				UFSD(("EXIT\n"))
+				return bh;
+			}
+			offset += SWAB16(de->d_reclen);
+			de = (struct ufs_dir_entry *)
+				((char *) de + SWAB16(de->d_reclen));
+		}
+
+		brelse (bh);
+		if (((block + NAMEI_RA_SIZE) << sb->s_blocksize_bits ) >=
+		    dir->i_size)
+			bh = NULL;
+		else
+			bh = ufs_getfrag (dir, block + NAMEI_RA_SIZE, 0, &err);
+		bh_use[block % NAMEI_RA_SIZE] = bh;
+		if (bh && !buffer_uptodate(bh))
+			bh_read[toread++] = bh;
+	}
+
+failed:
+	for (i = 0; i < NAMEI_RA_SIZE; ++i) brelse (bh_use[i]);
+	UFSD(("EXIT (FAILED)\n"))
+	return NULL;
+}
+
+int ufs_lookup(struct inode * dir, struct dentry *dentry)
+{
+	struct super_block * sb;
+	struct inode * inode;
+	struct ufs_dir_entry * de;
+	struct buffer_head * bh;
+	unsigned swab;
+	
+	UFSD(("ENTER\n"))
+	
+	sb = dir->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	
+	if (dentry->d_name.len > UFS_MAXNAMLEN)
+		return -ENAMETOOLONG;
+
+	bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+	inode = NULL;
+	if (bh) {
+		unsigned long ino = SWAB32(de->d_ino);
+		brelse (bh);
+		inode = iget(sb, ino);
+		if (!inode) 
+			return -EACCES;
+	}
+	d_add(dentry, inode);
+	UFSD(("EXIT\n"))
+	return 0;
+}
+
+/*
+ *	ufs_add_entry()
+ *
+ * adds a file entry to the specified directory, using the same
+ * semantics as ufs_find_entry(). It returns NULL if it failed.
+ *
+ * NOTE!! The inode part of 'de' is left at 0 - which means you
+ * may not sleep between calling this and putting something into
+ * the entry, as someone else might have used it while you slept.
+ */
+static struct buffer_head * ufs_add_entry (struct inode * dir,
+	const char * name, int namelen, struct ufs_dir_entry ** res_dir, 
+	int *err )
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	unsigned long offset;
+	unsigned fragoff;
+	unsigned short rec_len;
+	struct buffer_head * bh;
+	struct ufs_dir_entry * de, * de1;
+	unsigned flags, swab;
+
+	UFSD(("ENTER, name %s, namelen %u\n", name, namelen))
+	
+	*err = -EINVAL;
+	*res_dir = NULL;
+	if (!dir || !dir->i_nlink)
+		return NULL;
+		
+	sb = dir->i_sb;
+	flags = sb->u.ufs_sb.s_flags;
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+
+	if (namelen > UFS_MAXNAMLEN)
+	{
+		*err = -ENAMETOOLONG;
+		return NULL;
+	}
+
+	if (!namelen)
+		return NULL;
+	/*
+	 * Is this a busy deleted directory?  Can't create new files if so
+	 */
+	if (dir->i_size == 0)
+	{
+		*err = -ENOENT;
+		return NULL;
+	}
+	bh = ufs_bread (dir, 0, 0, err);
+	if (!bh)
+		return NULL;
+	rec_len = UFS_DIR_REC_LEN(namelen);
+	offset = 0;
+	de = (struct ufs_dir_entry *) bh->b_data;
+	*err = -ENOSPC;
+	while (1) {
+		if ((char *)de >= SECTOR_SIZE + bh->b_data) {
+			fragoff = offset & ~uspi->s_fmask;
+			if (fragoff != 0 && fragoff != SECTOR_SIZE)
+				ufs_error (sb, "ufs_add_entry", "internal error"
+					" fragoff %u", fragoff);
+			if (!fragoff) {
+				brelse (bh);
+				bh = NULL;
+				bh = ufs_bread (dir, offset >> sb->s_blocksize_bits, 1, err);
+			}
+			if (!bh)
+				return NULL;
+			if (dir->i_size <= offset) {
+				if (dir->i_size == 0) {
+					*err = -ENOENT;
+					return NULL;
+				}
+				de = (struct ufs_dir_entry *) (bh->b_data + fragoff);
+				de->d_ino = SWAB32(0);
+				de->d_reclen = SWAB16(SECTOR_SIZE);
+				de->d_u.d_namlen = SWAB16(0);
+				dir->i_size = offset + SECTOR_SIZE;
+				mark_inode_dirty(dir);
+			} else {
+				de = (struct ufs_dir_entry *) bh->b_data;
+			}
+		}
+		if (!ufs_check_dir_entry ("ufs_add_entry", dir, de, bh, offset)) {
+			*err = -ENOENT;
+			brelse (bh);
+			return NULL;
+		}
+		if (SWAB32(de->d_ino) != 0 && ufs_match (namelen, name, de, flags, swab)) {
+				*err = -EEXIST;
+				brelse (bh);
+				return NULL;
+		}
+		if ((SWAB32(de->d_ino) == 0 && SWAB16(de->d_reclen) >= rec_len) ||
+		    (SWAB16(de->d_reclen) >= UFS_DIR_REC_LEN(SWAB16(de->d_u.d_namlen)) + rec_len)) {
+			offset += SWAB16(de->d_reclen);
+			if (SWAB32(de->d_ino)) {
+				de1 = (struct ufs_dir_entry *) ((char *) de +
+					UFS_DIR_REC_LEN(SWAB16(de->d_u.d_namlen)));
+				de1->d_reclen = SWAB16(SWAB16(de->d_reclen) -
+					UFS_DIR_REC_LEN(SWAB16(de->d_u.d_namlen)));
+				de->d_reclen = SWAB16(UFS_DIR_REC_LEN(SWAB16(de->d_u.d_namlen)));
+				de = de1;
+			}
+			de->d_ino = SWAB32(0);
+			de->d_u.d_namlen = SWAB16(namelen);
+			memcpy (de->d_name, name, namelen + 1);
+			/*
+			 * XXX shouldn't update any times until successful
+			 * completion of syscall, but too many callers depend
+			 * on this.
+			 *
+			 * XXX similarly, too many callers depend on
+			 * ufs_new_inode() setting the times, but error
+			 * recovery deletes the inode, so the worst that can
+			 * happen is that the times are slightly out of date
+			 * and/or different from the directory change time.
+			 */
+			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+			mark_inode_dirty(dir);
+			dir->i_version = ++event;
+			mark_buffer_dirty(bh, 1);
+			*res_dir = de;
+			*err = 0;
+			
+			UFSD(("EXIT\n"))
+			return bh;
+		}
+		offset += SWAB16(de->d_reclen);
+		de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
+	}
+	brelse (bh);
+	UFSD(("EXIT (FAILED)\n"))
+	return NULL;
+}
+
+/*
+ * ufs_delete_entry deletes a directory entry by merging it with the
+ * previous entry.
+ */
+static int ufs_delete_entry (struct inode * inode, struct ufs_dir_entry * dir,
+	struct buffer_head * bh )
+	
+{
+	struct super_block * sb;
+	struct ufs_dir_entry * de, * pde;
+	unsigned i;
+	unsigned flags, swab;
+	
+	UFSD(("ENTER\n"))
+
+	sb = inode->i_sb;
+	flags = sb->u.ufs_sb.s_flags;
+	swab = sb->u.ufs_sb.s_swab;
+	i = 0;
+	pde = NULL;
+	de = (struct ufs_dir_entry *) bh->b_data;
+	
+	UFSD(("ino %u, reclen %u, namlen %u, name %s\n", SWAB32(de->d_ino),
+		SWAB16(de->d_reclen), ufs_namlen(de), de->d_name))
+
+	while (i < bh->b_size) {
+		if (!ufs_check_dir_entry ("ufs_delete_entry", inode, de, bh, i))
+			return -EIO;
+		if (de == dir)  {
+			if (pde)
+				pde->d_reclen =
+				    SWAB16(SWAB16(pde->d_reclen) +
+				    SWAB16(dir->d_reclen));
+			dir->d_ino = SWAB32(0);
+			UFSD(("EXIT\n"))
+			return 0;
+		}
+		i += SWAB16(de->d_reclen);
+		if (i == SECTOR_SIZE) pde = NULL;
+		else pde = de;
+		de = (struct ufs_dir_entry *)
+		    ((char *) de + SWAB16(de->d_reclen));
+		if (i == SECTOR_SIZE && SWAB16(de->d_reclen) == 0)
+			break;
+	}
+	UFSD(("EXIT\n"))
+	return -ENOENT;
+}
+
+/*
+ * By the time this is called, we already have created
+ * the directory cache entry for the new file, but it
+ * is so far negative - it has no inode.
+ *
+ * If the create succeeds, we fill in the inode information
+ * with d_instantiate(). 
+ */
+int ufs_create (struct inode * dir, struct dentry * dentry, int mode)
+{
+	struct super_block * sb;
+	struct inode * inode;
+	struct buffer_head * bh;
+	struct ufs_dir_entry * de;
+	int err = -EIO;
+	unsigned swab;
+	
+	sb = dir->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+
+	/*
+	 * N.B. Several error exits in ufs_new_inode don't set err.
+	 */
+	UFSD(("ENTER\n"))
+	
+	inode = ufs_new_inode (dir, mode, &err);
+	if (!inode)
+		return err;
+	inode->i_op = &ufs_file_inode_operations;
+	inode->i_mode = mode;
+	mark_inode_dirty(inode);
+	bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+	if (!bh) {
+		inode->i_nlink--;
+		mark_inode_dirty(inode);
+		iput (inode);
+		return err;
+	}
+	de->d_ino = SWAB32(inode->i_ino);
+	dir->i_version = ++event;
+	mark_buffer_dirty(bh, 1);
+	if (IS_SYNC(dir)) {
+		ll_rw_block (WRITE, 1, &bh);
+		wait_on_buffer (bh);
+	}
+	brelse (bh);
+	d_instantiate(dentry, inode);
+	
+	UFSD(("EXIT\n"))
+	
+	return 0;
+}
+
+int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
+{
+	struct super_block * sb;
+	struct inode * inode;
+	struct buffer_head * bh;
+	struct ufs_dir_entry * de;
+	int err = -EIO;
+	unsigned swab;
+	
+	sb = dir->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	
+	err = -ENAMETOOLONG;
+	if (dentry->d_name.len > UFS_MAXNAMLEN)
+		goto out;
+
+	inode = ufs_new_inode (dir, mode, &err);
+	if (!inode)
+		goto out;
+
+	inode->i_uid = current->fsuid;
+	inode->i_mode = mode;
+	inode->i_op = NULL;
+	if (S_ISREG(inode->i_mode))
+		inode->i_op = &ufs_file_inode_operations;
+	else if (S_ISDIR(inode->i_mode)) {
+		inode->i_op = &ufs_dir_inode_operations;
+		if (dir->i_mode & S_ISGID)
+			inode->i_mode |= S_ISGID;
+	}
+	else if (S_ISLNK(inode->i_mode))
+		inode->i_op = &ufs_symlink_inode_operations;
+	else if (S_ISCHR(inode->i_mode))
+		inode->i_op = &chrdev_inode_operations;
+	else if (S_ISBLK(inode->i_mode))
+		inode->i_op = &blkdev_inode_operations;
+	else if (S_ISFIFO(inode->i_mode)) 
+		init_fifo(inode);
+	if (S_ISBLK(mode) || S_ISCHR(mode))
+		inode->i_rdev = to_kdev_t(rdev);
+	mark_inode_dirty(inode);
+	bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+	if (!bh)
+		goto out_no_entry;
+	de->d_ino = SWAB32(inode->i_ino);
+	dir->i_version = ++event;
+	mark_buffer_dirty(bh, 1);
+	if (IS_SYNC(dir)) {
+		ll_rw_block (WRITE, 1, &bh);
+		wait_on_buffer (bh);
+	}
+	d_instantiate(dentry, inode);
+	brelse(bh);
+	err = 0;
+out:
+	return err;
+
+out_no_entry:
+	inode->i_nlink--;
+	mark_inode_dirty(inode);
+	iput(inode);
+	goto out;
+}
+
+int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+{
+	struct super_block * sb;
+	struct inode * inode;
+	struct buffer_head * bh, * dir_block;
+	struct ufs_dir_entry * de;
+	int err;
+	unsigned swab;
+	
+	sb = dir->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	
+	err = -ENAMETOOLONG;
+	if (dentry->d_name.len > UFS_MAXNAMLEN)
+		goto out;
+
+	err = -EMLINK;
+	if (dir->i_nlink >= UFS_LINK_MAX)
+		goto out;
+	err = -EIO;
+	inode = ufs_new_inode (dir, S_IFDIR, &err);
+	if (!inode)
+		goto out;
+
+	inode->i_op = &ufs_dir_inode_operations;
+	inode->i_size = SECTOR_SIZE;
+	dir_block = ufs_bread (inode, 0, 1, &err);
+	if (!dir_block) {
+		inode->i_nlink--; /* is this nlink == 0? */
+		mark_inode_dirty(inode);
+		iput (inode);
+		return err;
+	}
+	inode->i_blocks = sb->s_blocksize / SECTOR_SIZE;
+	de = (struct ufs_dir_entry *) dir_block->b_data;
+	de->d_ino = SWAB32(inode->i_ino);
+	de->d_u.d_namlen = SWAB16(1);
+	de->d_reclen = SWAB16(UFS_DIR_REC_LEN(1));
+	strcpy (de->d_name, ".");
+	de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
+	de->d_ino = SWAB32(dir->i_ino);
+	de->d_reclen = SWAB16(SECTOR_SIZE - UFS_DIR_REC_LEN(1));
+	de->d_u.d_namlen = SWAB16(2);
+	strcpy (de->d_name, "..");
+	inode->i_nlink = 2;
+	mark_buffer_dirty(dir_block, 1);
+	brelse (dir_block);
+	inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask);
+	if (dir->i_mode & S_ISGID)
+		inode->i_mode |= S_ISGID;
+	mark_inode_dirty(inode);
+	bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+	if (!bh)
+		goto out_no_entry;
+	de->d_ino = SWAB32(inode->i_ino);
+	dir->i_version = ++event;
+	mark_buffer_dirty(bh, 1);
+	if (IS_SYNC(dir)) {
+		ll_rw_block (WRITE, 1, &bh);
+		wait_on_buffer (bh);
+	}
+	dir->i_nlink++;
+	mark_inode_dirty(dir);
+	d_instantiate(dentry, inode);
+	brelse (bh);
+	err = 0;
+out:
+	return err;
+
+out_no_entry:
+	inode->i_nlink = 0;
+	mark_inode_dirty(inode);
+	iput (inode);
+	goto out;
+}
+
+/*
+ * routine to check that the specified directory is empty (for rmdir)
+ */
+static int ufs_empty_dir (struct inode * inode)
+{
+	struct super_block * sb;
+	unsigned long offset;
+	struct buffer_head * bh;
+	struct ufs_dir_entry * de, * de1;
+	int err;
+	unsigned swab;	
+	
+	sb = inode->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+
+	if (inode->i_size < UFS_DIR_REC_LEN(1) + UFS_DIR_REC_LEN(2) ||
+	    !(bh = ufs_bread (inode, 0, 0, &err))) {
+	    	ufs_warning (inode->i_sb, "empty_dir",
+			      "bad directory (dir #%lu) - no data block",
+			      inode->i_ino);
+		return 1;
+	}
+	de = (struct ufs_dir_entry *) bh->b_data;
+	de1 = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
+	if (SWAB32(de->d_ino) != inode->i_ino || !SWAB32(de1->d_ino) || 
+	    strcmp (".", de->d_name) || strcmp ("..", de1->d_name)) {
+	    	ufs_warning (inode->i_sb, "empty_dir",
+			      "bad directory (dir #%lu) - no `.' or `..'",
+			      inode->i_ino);
+		return 1;
+	}
+	offset = SWAB16(de->d_reclen) + SWAB16(de1->d_reclen);
+	de = (struct ufs_dir_entry *) ((char *) de1 + SWAB16(de1->d_reclen));
+	while (offset < inode->i_size ) {
+		if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
+			brelse (bh);
+			bh = ufs_bread (inode, offset >> sb->s_blocksize_bits, 1, &err);
+	 		if (!bh) {
+				ufs_error (sb, "empty_dir",
+					    "directory #%lu contains a hole at offset %lu",
+					    inode->i_ino, offset);
+				offset += sb->s_blocksize;
+				continue;
+			}
+			de = (struct ufs_dir_entry *) bh->b_data;
+		}
+		if (!ufs_check_dir_entry ("empty_dir", inode, de, bh, offset)) {
+			brelse (bh);
+			return 1;
+		}
+		if (SWAB32(de->d_ino)) {
+			brelse (bh);
+			return 0;
+		}
+		offset += SWAB16(de->d_reclen);
+		de = (struct ufs_dir_entry *) ((char *) de + SWAB16(de->d_reclen));
+	}
+	brelse (bh);
+	return 1;
+}
+
+int ufs_rmdir (struct inode * dir, struct dentry *dentry)
+{
+	struct super_block *sb;
+	int retval;
+	struct inode * inode;
+	struct buffer_head * bh;
+	struct ufs_dir_entry * de;
+	unsigned swab;
+	
+	sb = dir->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+		
+	UFSD(("ENTER\n"))
+	
+	retval = -ENAMETOOLONG;
+	if (dentry->d_name.len > UFS_MAXNAMLEN)
+		goto out;
+
+	retval = -ENOENT;
+	bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+	if (!bh)
+		goto end_rmdir;
+
+	inode = dentry->d_inode;
+	if (inode->i_sb->dq_op)
+		inode->i_sb->dq_op->initialize (inode, -1);
+
+	retval = -EPERM;
+	if ((dir->i_mode & S_ISVTX) && 
+	    current->fsuid != inode->i_uid &&
+	    current->fsuid != dir->i_uid && !fsuser())
+		goto end_rmdir;
+	if (inode == dir)	/* we may not delete ".", but "../dir" is ok */
+		goto end_rmdir;
+
+	retval = -ENOTDIR;
+	if (!S_ISDIR(inode->i_mode))
+		goto end_rmdir;
+
+	retval = -EIO;
+	if (inode->i_dev != dir->i_dev)
+		goto end_rmdir;
+	if (SWAB32(de->d_ino) != inode->i_ino)
+		goto end_rmdir;
+
+	down(&inode->i_sem);
+	/*
+	 * Prune any child dentries so that this dentry becomes negative.
+	 */
+	if (dentry->d_count > 1) {
+		ufs_warning (sb, "ufs_rmdir", "d_count=%d, pruning\n", dentry->d_count);
+		shrink_dcache_parent(dentry);
+	}
+	if (!ufs_empty_dir (inode))
+		retval = -ENOTEMPTY;
+	else if (SWAB32(de->d_ino) != inode->i_ino)
+		retval = -ENOENT;
+	else {
+		if (dentry->d_count > 1) {
+		/*
+		 * Are we deleting the last instance of a busy directory?
+		 * Better clean up if so.
+		 *
+		 * Make directory empty (it will be truncated when finally
+		 * dereferenced).  This also inhibits ufs_add_entry.
+		 */
+			inode->i_size = 0;
+		}
+		retval = ufs_delete_entry (dir, de, bh);
+		dir->i_version = ++event;
+	}
+	up(&inode->i_sem);
+	if (retval)
+		goto end_rmdir;
+	mark_buffer_dirty(bh, 1);
+	if (IS_SYNC(dir)) {
+		ll_rw_block (WRITE, 1, &bh);
+		wait_on_buffer (bh);
+	}
+	if (inode->i_nlink != 2)
+		ufs_warning (inode->i_sb, "ufs_rmdir",
+			      "empty directory has nlink!=2 (%d)",
+			      inode->i_nlink);
+	inode->i_version = ++event;
+	inode->i_nlink = 0;
+	mark_inode_dirty(inode);
+	dir->i_nlink--;
+	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+	mark_inode_dirty(dir);
+	d_delete(dentry);
+
+end_rmdir:
+	brelse (bh);
+out:
+	UFSD(("EXIT\n"))
+	
+	return retval;
+}
+
+int ufs_unlink(struct inode * dir, struct dentry *dentry)
+{
+	struct super_block * sb;
+	int retval;
+	struct inode * inode;
+	struct buffer_head * bh;
+	struct ufs_dir_entry * de;
+	unsigned flags, swab;
+
+	sb = dir->i_sb;
+	flags = sb->u.ufs_sb.s_flags;
+	swab = sb->u.ufs_sb.s_swab;
+		
+	retval = -ENAMETOOLONG;
+	if (dentry->d_name.len > UFS_MAXNAMLEN)
+		goto out;
+
+	retval = -ENOENT;
+	bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+	UFSD(("de: ino %u, reclen %u, namelen %u, name %s\n", SWAB32(de->d_ino),
+		SWAB16(de->d_reclen), ufs_namlen(de), de->d_name))
+	if (!bh)
+		goto end_unlink;
+
+	inode = dentry->d_inode;
+	if (inode->i_sb->dq_op)
+		inode->i_sb->dq_op->initialize (inode, -1);
+
+	retval = -EPERM;
+	if (S_ISDIR(inode->i_mode))
+		goto end_unlink;
+	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+		goto end_unlink;
+	if ((dir->i_mode & S_ISVTX) &&
+	    current->fsuid != inode->i_uid &&
+	    current->fsuid != dir->i_uid && !fsuser())
+		goto end_unlink;
+
+	retval = -EIO;
+	if (SWAB32(de->d_ino) != inode->i_ino)
+		goto end_unlink;
+	
+	if (!inode->i_nlink) {
+		ufs_warning (inode->i_sb, "ufs_unlink",
+			      "Deleting nonexistent file (%lu), %d",
+			      inode->i_ino, inode->i_nlink);
+		inode->i_nlink = 1;
+	}
+	retval = ufs_delete_entry (dir, de, bh);
+	if (retval)
+		goto end_unlink;
+	dir->i_version = ++event;
+	mark_buffer_dirty(bh, 1);
+	if (IS_SYNC(dir)) {
+		ll_rw_block (WRITE, 1, &bh);
+		wait_on_buffer (bh);
+	}
+	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+	mark_inode_dirty(dir);
+	inode->i_nlink--;
+	mark_inode_dirty(inode);
+	inode->i_ctime = dir->i_ctime;
+	retval = 0;
+	d_delete(dentry);	/* This also frees the inode */
+
+end_unlink:
+	brelse (bh);
+out:
+	return retval;
+}
+
+
+int ufs_link (struct dentry * old_dentry, struct inode * dir,
+	struct dentry *dentry)
+{
+	struct super_block * sb;
+	struct inode *inode = old_dentry->d_inode;
+	struct ufs_dir_entry * de;
+	struct buffer_head * bh;
+	int err;
+	unsigned swab;
+
+	inode = old_dentry->d_inode;
+	sb = inode->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	
+	if (S_ISDIR(inode->i_mode))
+		return -EPERM;
+
+	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+		return -EPERM;
+
+	if (inode->i_nlink >= UFS_LINK_MAX)
+		return -EMLINK;
+
+	bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+	if (!bh)
+		return err;
+
+	de->d_ino = SWAB32(inode->i_ino);
+	dir->i_version = ++event;
+	mark_buffer_dirty(bh, 1);
+	if (IS_SYNC(dir)) {
+		ll_rw_block (WRITE, 1, &bh);
+		wait_on_buffer (bh);
+	}
+	brelse (bh);
+	inode->i_nlink++;
+	inode->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(inode);
+	inode->i_count++;
+	d_instantiate(dentry, inode);
+	return 0;
+}
+
+/*
+ * Create symbolic link. We use only slow symlinks at this time.
+ */
+int ufs_symlink (struct inode * dir, struct dentry * dentry,
+	const char * symname)
+{
+	struct super_block * sb;
+	struct ufs_dir_entry * de;
+	struct inode * inode;
+	struct buffer_head * bh, * name_block;
+	char * link;
+	unsigned i, l;
+	int err;
+	char c;
+	unsigned swab;
+	
+	UFSD(("ENTER\n"))
+	
+	sb = dir->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	bh = name_block = NULL;
+	err = -EIO;
+	
+	if (!(inode = ufs_new_inode (dir, S_IFLNK, &err))) {
+		return err;
+	}
+	inode->i_mode = S_IFLNK | S_IRWXUGO;
+	inode->i_op = &ufs_symlink_inode_operations;
+	for (l = 0; l < sb->s_blocksize - 1 && symname [l]; l++);
+
+	/***if (l >= sizeof (inode->u.ufs_i.i_data)) {***/
+	if (1) {
+		/* slow symlink */
+		name_block = ufs_bread (inode, 0, 1, &err);
+		if (!name_block) {
+			inode->i_nlink--;
+			mark_inode_dirty(inode);
+			iput (inode);
+			return err;
+		}
+		link = name_block->b_data;
+		
+	} else {
+		/* fast symlink */
+		link = (char *) inode->u.ufs_i.i_u1.i_data;
+	}
+	i = 0;
+	while (i < sb->s_blocksize - 1 && (c = *(symname++)))
+		link[i++] = c;
+	link[i] = 0;
+	if (name_block) {
+		mark_buffer_dirty(name_block, 1);
+		brelse (name_block);
+	}
+	inode->i_size = i;
+	mark_inode_dirty(inode);
+
+	bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+	if (!bh)
+		goto out_no_entry;
+	de->d_ino = SWAB32(inode->i_ino);
+	dir->i_version = ++event;
+	mark_buffer_dirty(bh, 1);
+	if (IS_SYNC(dir)) {
+		ll_rw_block (WRITE, 1, &bh);
+		wait_on_buffer (bh);
+	}
+	brelse (bh);
+	d_instantiate(dentry, inode);
+	err = 0;
+out:
+	return err;
+
+out_no_entry:
+	inode->i_nlink--;
+	mark_inode_dirty(inode);
+	iput (inode);
+	goto out;
+}
+
+
+#define PARENT_INO(buffer) \
+	((struct ufs_dir_entry *) ((char *) buffer + \
+	SWAB16(((struct ufs_dir_entry *) buffer)->d_reclen)))->d_ino
+/*
+ * rename uses retrying to avoid race-conditions: at least they should be
+ * minimal.
+ * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
+ * checks fail, it tries to restart itself again. Very practical - no changes
+ * are done until we know everything works ok.. and then all the changes can be
+ * done in one fell swoop when we have claimed all the buffers needed.
+ *
+ * Anybody can rename anything with this: the permission checks are left to the
+ * higher-level routines.
+ */
+static int do_ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
+	struct inode * new_dir,	struct dentry * new_dentry )
+{
+	struct super_block * sb;
+	struct inode * old_inode, * new_inode;
+	struct buffer_head * old_bh, * new_bh, * dir_bh;
+	struct ufs_dir_entry * old_de, * new_de;
+	int retval;
+	unsigned flags, swab;
+	
+	sb = old_dir->i_sb;
+	flags = sb->u.ufs_sb.s_flags;
+	swab = sb->u.ufs_sb.s_swab;
+
+	UFSD(("ENTER\n"))
+	
+	old_inode = new_inode = NULL;
+	old_bh = new_bh = dir_bh = NULL;
+	new_de = NULL;
+	retval = -ENAMETOOLONG;
+	if (old_dentry->d_name.len > UFS_MAXNAMLEN)
+		goto end_rename;
+
+	UFSD(("name %s, len %u\n", old_dentry->d_name.name, old_dentry->d_name.len)) 
+	old_bh = ufs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
+	UFSD(("ino %u, reclen %u, namlen %u, name %s\n", SWAB32(old_de->d_ino),
+		SWAB16(old_de->d_reclen), ufs_namlen(old_de), old_de->d_name))
+	    
+	retval = -ENOENT;
+	if (!old_bh)
+		goto end_rename;
+	old_inode = old_dentry->d_inode;
+
+	retval = -EPERM;
+	if ((old_dir->i_mode & S_ISVTX) && 
+	    current->fsuid != old_inode->i_uid &&
+	    current->fsuid != old_dir->i_uid && !fsuser())
+		goto end_rename;
+	if (IS_APPEND(old_inode) || IS_IMMUTABLE(old_inode))
+		goto end_rename;
+
+	new_inode = new_dentry->d_inode;
+	UFSD(("name %s, len %u\n", new_dentry->d_name.name, new_dentry->d_name.len)) 
+	new_bh = ufs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de);
+	if (new_bh) {
+		if (!new_inode) {
+			brelse (new_bh);
+			new_bh = NULL;
+		} else {
+			if (new_inode->i_sb->dq_op)
+				new_inode->i_sb->dq_op->initialize (new_inode, -1);
+		}
+	}
+	retval = 0;
+	if (new_inode == old_inode)
+		goto end_rename;
+	if (new_inode && S_ISDIR(new_inode->i_mode)) {
+		retval = -EISDIR;
+		if (!S_ISDIR(old_inode->i_mode))
+			goto end_rename;
+		retval = -EINVAL;
+		if (is_subdir(new_dentry, old_dentry))
+			goto end_rename;
+		retval = -ENOTEMPTY;
+		if (!ufs_empty_dir (new_inode))
+			goto end_rename;
+		retval = -EBUSY;
+		if (new_dentry->d_count > 1)
+			goto end_rename;
+	}
+	retval = -EPERM;
+	if (new_inode) {
+		if ((new_dir->i_mode & S_ISVTX) &&
+		    current->fsuid != new_inode->i_uid &&
+		    current->fsuid != new_dir->i_uid && !fsuser())
+			goto end_rename;
+		if (IS_APPEND(new_inode) || IS_IMMUTABLE(new_inode))
+			goto end_rename;
+	}
+	if (S_ISDIR(old_inode->i_mode)) {
+		retval = -ENOTDIR;
+		if (new_inode && !S_ISDIR(new_inode->i_mode))
+			goto end_rename;
+		retval = -EINVAL;
+		if (is_subdir(new_dentry, old_dentry))
+			goto end_rename;
+		dir_bh = ufs_bread (old_inode, 0, 0, &retval);
+		if (!dir_bh)
+			goto end_rename;
+		if (SWAB32(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)
+			goto end_rename;
+		retval = -EMLINK;
+		if (!new_inode && new_dir->i_nlink >= UFS_LINK_MAX)
+			goto end_rename;
+	}
+
+	if (!new_bh)
+		new_bh = ufs_add_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de,
+					 &retval);
+	if (!new_bh)
+		goto end_rename;
+	new_dir->i_version = ++event;
+
+	/*
+	 * ok, that's it
+	 */
+	new_de->d_ino = SWAB32(old_inode->i_ino);
+	ufs_delete_entry (old_dir, old_de, old_bh);
+
+	old_dir->i_version = ++event;
+	if (new_inode) {
+		new_inode->i_nlink--;
+		new_inode->i_ctime = CURRENT_TIME;
+		mark_inode_dirty(new_inode);
+	}
+	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+	mark_inode_dirty(old_dir);
+	if (dir_bh) {
+		PARENT_INO(dir_bh->b_data) = SWAB32(new_dir->i_ino);
+		mark_buffer_dirty(dir_bh, 1);
+		old_dir->i_nlink--;
+		mark_inode_dirty(old_dir);
+		if (new_inode) {
+			new_inode->i_nlink--;
+			mark_inode_dirty(new_inode);
+		} else {
+			new_dir->i_nlink++;
+			mark_inode_dirty(new_dir);
+		}
+	}
+	mark_buffer_dirty(old_bh,  1);
+	if (IS_SYNC(old_dir)) {
+		ll_rw_block (WRITE, 1, &old_bh);
+		wait_on_buffer (old_bh);
+	}
+	
+	mark_buffer_dirty(new_bh, 1);
+	if (IS_SYNC(new_dir)) {
+		ll_rw_block (WRITE, 1, &new_bh);
+		wait_on_buffer (new_bh);
+	}
+
+	/* Update the dcache */
+	d_move(old_dentry, new_dentry);
+	retval = 0;
+end_rename:
+	brelse (dir_bh);
+	brelse (old_bh);
+	brelse (new_bh);
+	
+	UFSD(("EXIT\n"))
+	
+	return retval;
+}
+
+/*
+ * Ok, rename also locks out other renames, as they can change the parent of
+ * a directory, and we don't want any races. Other races are checked for by
+ * "do_rename()", which restarts if there are inconsistencies.
+ *
+ * Note that there is no race between different filesystems: it's only within
+ * the same device that races occur: many renames can happen at once, as long
+ * as they are on different partitions.
+ *
+ * In the second extended file system, we use a lock flag stored in the memory
+ * super-block.  This way, we really lock other renames only if they occur
+ * on the same file system
+ */
+int ufs_rename (struct inode * old_dir, struct dentry *old_dentry,
+	struct inode * new_dir,	struct dentry *new_dentry )
+{
+	int result;
+
+	UFSD(("ENTER\n"))
+	
+	while (old_dir->i_sb->u.ufs_sb.s_rename_lock)
+		sleep_on (&old_dir->i_sb->u.ufs_sb.s_rename_wait);
+	old_dir->i_sb->u.ufs_sb.s_rename_lock = 1;
+	result = do_ufs_rename (old_dir, old_dentry, new_dir, new_dentry);
+	old_dir->i_sb->u.ufs_sb.s_rename_lock = 0;
+	wake_up (&old_dir->i_sb->u.ufs_sb.s_rename_wait);
+	
+	UFSD(("EXIT\n"))
+	
+	return result;
+}
+ 
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/super.c linux/fs/ufs/super.c
--- v2.1.111/linux/fs/ufs/super.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/ufs/super.c	Sun Jul 26 01:20:22 1998
@@ -0,0 +1,690 @@
+/*
+ *  linux/fs/ufs/super.c
+ *
+ * Copyright (C) 1996
+ * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
+ * Laboratory for Computer Science Research Computing Facility
+ * Rutgers, The State University of New Jersey
+ *
+ * Copyright (C) 1996  Eddie C. Dost  (ecd@skynet.be)
+ *
+ * Kernel module support added on 96/04/26 by
+ * Stefan Reinauer <stepan@home.culture.mipt.ru>
+ *
+ * Module usage counts added on 96/04/29 by
+ * Gertjan van Wingerde <gertjan@cs.vu.nl>
+ *
+ * Clean swab support on 19970406 by
+ * Francois-Rene Rideau <rideau@ens.fr>
+ *
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
+ *
+ * NeXTstep support added on February 5th 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk>.
+ *
+ * write support Daniel Pirkl <daniel.pirkl@email.cz> 1998
+ * 
+ 
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/locks.h>
+#include <asm/uaccess.h>
+#include <linux/malloc.h>
+
+#include "swab.h"
+#include "util.h"
+
+
+#undef UFS_SUPER_DEBUG
+#undef UFS_SUPER_DEBUG_MORE
+
+#ifdef UFS_SUPER_DEBUG
+#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+#ifdef UFS_SUPER_DEBUG_MORE
+/*
+ * Print contents of ufs_super_block, useful for debuging
+ */
+void ufs_print_super_stuff(struct ufs_super_block_first * usb1,
+	struct ufs_super_block_second * usb2, 
+	struct ufs_super_block_third * usb3, unsigned swab)
+{
+	printk("\nufs_print_super_stuff\n");
+	printk("size of usb:    %lu\n", sizeof(struct ufs_super_block));
+	printk("  magic:        0x%x\n", SWAB32(usb3->fs_magic));
+	printk("  sblkno:       %u\n", SWAB32(usb1->fs_sblkno));
+	printk("  cblkno:       %u\n", SWAB32(usb1->fs_cblkno));
+	printk("  iblkno:       %u\n", SWAB32(usb1->fs_iblkno));
+	printk("  dblkno:       %u\n", SWAB32(usb1->fs_dblkno));
+	printk("  cgoffset:     %u\n", SWAB32(usb1->fs_cgoffset));
+	printk("  ~cgmask:      0x%x\n", ~SWAB32(usb1->fs_cgmask));
+	printk("  size:         %u\n", SWAB32(usb1->fs_size));
+	printk("  dsize:        %u\n", SWAB32(usb1->fs_dsize));
+	printk("  ncg:          %u\n", SWAB32(usb1->fs_ncg));
+	printk("  bsize:        %u\n", SWAB32(usb1->fs_bsize));
+	printk("  fsize:        %u\n", SWAB32(usb1->fs_fsize));
+	printk("  frag:         %u\n", SWAB32(usb1->fs_frag));
+	printk("  fragshift:    %u\n", SWAB32(usb1->fs_fragshift));
+	printk("  ~fmask:       %u\n", ~SWAB32(usb1->fs_fmask));
+	printk("  fshift:       %u\n", SWAB32(usb1->fs_fshift));
+	printk("  sbsize:       %u\n", SWAB32(usb1->fs_sbsize));
+	printk("  spc:          %u\n", SWAB32(usb1->fs_spc));
+	printk("  cpg:          %u\n", SWAB32(usb1->fs_cpg));
+	printk("  ipg:          %u\n", SWAB32(usb1->fs_ipg));
+	printk("  fpg:          %u\n", SWAB32(usb1->fs_fpg));
+	printk("  csaddr:       %u\n", SWAB32(usb1->fs_csaddr));
+	printk("  cssize:       %u\n", SWAB32(usb1->fs_cssize));
+	printk("  cgsize:       %u\n", SWAB32(usb1->fs_cgsize));
+	printk("  fstodb:       %u\n", SWAB32(usb1->fs_fsbtodb));
+	printk("  postblformat: %u\n", SWAB32(usb3->fs_postblformat));
+	printk("  nrpos:        %u\n", SWAB32(usb3->fs_nrpos));
+	printk("  ndir          %u\n", SWAB32(usb1->fs_cstotal.cs_ndir));
+	printk("  nifree        %u\n", SWAB32(usb1->fs_cstotal.cs_nifree));
+	printk("  nbfree        %u\n", SWAB32(usb1->fs_cstotal.cs_nbfree));
+	printk("  nffree        %u\n", SWAB32(usb1->fs_cstotal.cs_nffree));
+}
+
+
+/*
+ * Print contents of ufs_cylinder_group, useful for debuging
+ */
+void ufs_print_cylinder_stuff(struct ufs_cylinder_group *cg, unsigned swab)
+{
+	printk("\nufs_print_cylinder_stuff\n");
+	printk("size of ucg: %lu\n", sizeof(struct ufs_cylinder_group));
+	printk("  magic:       %x\n", SWAB32(cg->cg_magic));
+	printk("  time:        %u\n", SWAB32(cg->cg_time));
+	printk("  cgx:         %u\n", SWAB32(cg->cg_cgx));
+	printk("  ncyl:        %u\n", SWAB16(cg->cg_ncyl));
+	printk("  niblk:       %u\n", SWAB16(cg->cg_niblk));
+	printk("  ndblk:       %u\n", SWAB32(cg->cg_ndblk));
+	printk("  cs_ndir:     %u\n", SWAB32(cg->cg_cs.cs_ndir));
+	printk("  cs_nbfree:   %u\n", SWAB32(cg->cg_cs.cs_nbfree));
+	printk("  cs_nifree:   %u\n", SWAB32(cg->cg_cs.cs_nifree));
+	printk("  cs_nffree:   %u\n", SWAB32(cg->cg_cs.cs_nffree));
+	printk("  rotor:       %u\n", SWAB32(cg->cg_rotor));
+	printk("  frotor:      %u\n", SWAB32(cg->cg_frotor));
+	printk("  irotor:      %u\n", SWAB32(cg->cg_irotor));
+	printk("  frsum:       %u, %u, %u, %u, %u, %u, %u, %u\n",
+	    SWAB32(cg->cg_frsum[0]), SWAB32(cg->cg_frsum[1]),
+	    SWAB32(cg->cg_frsum[2]), SWAB32(cg->cg_frsum[3]),
+	    SWAB32(cg->cg_frsum[4]), SWAB32(cg->cg_frsum[5]),
+	    SWAB32(cg->cg_frsum[6]), SWAB32(cg->cg_frsum[7]));
+	printk("  btotoff:     %u\n", SWAB32(cg->cg_btotoff));
+	printk("  boff:        %u\n", SWAB32(cg->cg_boff));
+	printk("  iuseoff:     %u\n", SWAB32(cg->cg_iusedoff));
+	printk("  freeoff:     %u\n", SWAB32(cg->cg_freeoff));
+	printk("  nextfreeoff: %u\n", SWAB32(cg->cg_nextfreeoff));
+}
+#endif /* UFS_SUPER_DEBUG_MORE */
+
+/*
+ * Called while file system is mounted, read super block
+ * and create important imtermal structures.
+ */
+struct super_block * ufs_read_super (
+	struct super_block * sb,
+	void * data,
+	int silent)
+{
+	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block_first * usb1;
+	struct ufs_super_block_second * usb2;
+	struct ufs_super_block_third * usb3;
+	struct ufs_buffer_head * ubh;
+	unsigned char * base, * space;
+	unsigned size, blks, i;
+	unsigned block_size, super_block_size;
+	unsigned flags, swab;
+	s64 tmp;
+	static unsigned offsets[] = {0, 96, 160};  /* different superblock locations */
+	            
+	UFSD(("ENTER\n"))
+	
+	uspi = NULL;
+	ubh = NULL;
+	base = space = NULL;
+	sb->u.ufs_sb.s_ucg = NULL;
+	flags = 0;
+	swab = 0;
+	
+	/* sb->s_dev and sb->s_flags are set by our caller
+	 * data is the mystery argument to sys_mount()
+	 *
+	 * Our caller also sets s_dev, s_covered, s_rd_only, s_dirt,
+ 	 *   and s_type when we return.
+	 */
+
+	MOD_INC_USE_COUNT;
+	lock_super (sb);
+
+	sb->u.ufs_sb.s_uspi = uspi = 
+		kmalloc (sizeof(struct ufs_sb_private_info), GFP_KERNEL);
+	if (!uspi)
+		goto failed;
+	
+	block_size = BLOCK_SIZE;
+	super_block_size = BLOCK_SIZE * 2;
+	
+	uspi->s_fsize = block_size;
+	uspi->s_fmask = ~(BLOCK_SIZE - 1);
+	uspi->s_fshift = BLOCK_SIZE_BITS;
+	uspi->s_sbsize = super_block_size;
+	i = 0;
+	uspi->s_sbbase = offsets[i];
+	
+again:	
+	set_blocksize (sb->s_dev, block_size);
+
+	/*
+	 * read ufs super block from device
+	 */
+	ubh = ubh_bread2 (sb->s_dev, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size);
+	if (!ubh) 
+		goto failed;
+	
+	usb1 = ubh_get_usb_first(USPI_UBH);
+	usb2 = ubh_get_usb_second(USPI_UBH);
+	usb3 = ubh_get_usb_third(USPI_UBH);
+	
+	/*
+	 * Check ufs magic number
+	 */
+	if (usb3->fs_magic != UFS_MAGIC) {
+		switch (le32_to_cpup(&usb3->fs_magic)) {
+		case UFS_MAGIC:
+			swab = UFS_LITTLE_ENDIAN; break;
+		case UFS_CIGAM:
+			swab = UFS_BIG_ENDIAN; break;
+		default:
+			/*
+			 * Try another super block location
+			 */
+			if (++i < sizeof(offsets)/sizeof(unsigned)) {
+				ubh_brelse2(ubh);
+				ubh = NULL;
+				uspi->s_sbbase = offsets[i];
+				goto again;
+			}
+			else {
+				printk("ufs_read_super: super block loacation not in { 0, 96, 160} or bad magic number\n");
+				goto failed;
+			}
+		}
+	}
+	
+	/*
+	 * Check block and fragment sizes
+	 */
+	uspi->s_bsize = SWAB32(usb1->fs_bsize);
+	uspi->s_fsize = SWAB32(usb1->fs_fsize);
+	uspi->s_sbsize = SWAB32(usb1->fs_sbsize);
+
+	if (uspi->s_bsize != 4096 && uspi->s_bsize != 8192) {
+		printk("ufs_read_super: fs_bsize %u != {4096, 8192}\n", uspi->s_bsize);
+		goto failed;
+	}
+	if (uspi->s_fsize != 512 && uspi->s_fsize != 1024) {
+		printk("ufs_read_super: fs_fsize %u != {512, 1024}\n", uspi->s_fsize);
+	        goto failed;
+	}
+	
+	/*
+	 * Block size is not 1024, set block_size to 512, 
+	 * free buffers and read it again
+	 */
+	if (uspi->s_fsize != block_size || uspi->s_sbsize != super_block_size) {
+		ubh_brelse2(ubh);
+		ubh = NULL;
+		uspi->s_fmask = SWAB32(usb1->fs_fmask);
+		uspi->s_fshift = SWAB32(usb1->fs_fshift);
+		goto again;
+	}
+
+#ifdef UFS_SUPER_DEBUG_MORE
+	ufs_print_super_stuff (usb1, usb2, usb3, swab);
+#endif
+	/*
+	 * Check file system type
+	 */
+	flags |= UFS_VANILLA;
+	/* XXX more consistency check */
+	UFSD(("ufs_read_super: maxsymlinklen 0x%8.8x\n", usb3->fs_u.fs_44.fs_maxsymlinklen))
+	if (usb3->fs_u.fs_44.fs_maxsymlinklen >= 0) {
+		if (usb3->fs_u.fs_44.fs_inodefmt >= UFS_44INODEFMT) {
+			UFSD(("44BSD\n"))
+			flags |= UFS_44BSD;
+			sb->s_flags |= MS_RDONLY;
+		} else {
+			UFSD(("OLD\n"))
+			sb->s_flags |= UFS_OLD;       /* 4.2BSD */
+		}
+	} else if (uspi->s_sbbase > 0) {
+		UFSD(("NEXT\n"))
+		flags |= UFS_NEXT;
+		sb->s_flags |= MS_RDONLY;
+	} else {
+		UFSD(("SUN\n"))
+		flags |= UFS_SUN;
+        }
+
+	/*
+	 * Check, if file system was correctly unmounted.
+	 * If not, make it read only.
+	 */
+        if (((flags & UFS_ST_MASK) == UFS_ST_44BSD) ||
+            ((flags & UFS_ST_MASK) == UFS_ST_OLD) ||
+            ((flags & UFS_ST_MASK) == UFS_ST_NEXT) ||
+            (((flags & UFS_ST_MASK) == UFS_ST_SUN) &&
+            ufs_state(usb3) == UFS_FSOK - usb1->fs_time)) {
+		switch(usb1->fs_clean) {
+		    case UFS_FSCLEAN:
+			UFSD(("fs is clean\n"))
+			break;
+		    case UFS_FSSTABLE:
+			UFSD(("fs is stable\n"))
+			break;
+		    case UFS_FSACTIVE:
+			printk("ufs_read_super: fs is active\n");
+			sb->s_flags |= MS_RDONLY;
+			break;
+		    case UFS_FSBAD:
+			printk("ufs_read_super: fs is bad\n");
+			sb->s_flags |= MS_RDONLY;
+			break;
+		    default:
+			printk("ufs_read_super: can't grok fs_clean 0x%x\n",
+				usb1->fs_clean);
+			sb->s_flags |= MS_RDONLY;
+			break;
+		}
+	} else {
+		printk("ufs_read_super: fs needs fsck\n");
+		sb->s_flags |= MS_RDONLY;
+	}
+
+	sb->s_flags &= ~MS_RDONLY;
+	/*
+	 * Read ufs_super_block into internal data structures
+	 */
+	sb->s_blocksize =  SWAB32(usb1->fs_fsize);
+	sb->s_blocksize_bits = SWAB32(usb1->fs_fshift);
+	sb->s_op = &ufs_super_ops;
+	sb->dq_op = 0; /* XXX */
+	sb->s_magic = SWAB32(usb3->fs_magic);
+
+	uspi->s_sblkno = SWAB32(usb1->fs_sblkno);
+	uspi->s_cblkno = SWAB32(usb1->fs_cblkno);
+	uspi->s_iblkno = SWAB32(usb1->fs_iblkno);
+	uspi->s_dblkno = SWAB32(usb1->fs_dblkno);
+	uspi->s_cgoffset = SWAB32(usb1->fs_cgoffset);
+	uspi->s_cgmask = SWAB32(usb1->fs_cgmask);
+	uspi->s_size = SWAB32(usb1->fs_size);
+	uspi->s_dsize = SWAB32(usb1->fs_dsize);
+	uspi->s_ncg = SWAB32(usb1->fs_ncg);
+	/* s_bsize already set */
+	/* s_fsize already set */
+	uspi->s_fpb = SWAB32(usb1->fs_frag);
+        uspi->s_minfree = SWAB32(usb1->fs_minfree);
+	uspi->s_bmask = SWAB32(usb1->fs_bmask);
+	uspi->s_fmask = SWAB32(usb1->fs_fmask);
+	uspi->s_bshift = SWAB32(usb1->fs_bshift);
+	uspi->s_fshift = SWAB32(usb1->fs_fshift);
+	uspi->s_fpbshift = SWAB32(usb1->fs_fragshift);
+	uspi->s_fsbtodb = SWAB32(usb1->fs_fsbtodb);
+	/* s_sbsize already set */
+	uspi->s_csmask = SWAB32(usb1->fs_csmask);
+	uspi->s_csshift = SWAB32(usb1->fs_csshift);
+        uspi->s_nindir = SWAB32(usb1->fs_nindir);
+	uspi->s_inopb = SWAB32(usb1->fs_inopb);
+	uspi->s_nspf = SWAB32(usb1->fs_nspf);
+	uspi->s_npsect = SWAB32(usb1->fs_npsect);
+	uspi->s_interleave = SWAB32(usb1->fs_interleave);
+	uspi->s_trackskew = SWAB32(usb1->fs_trackskew);
+	uspi->s_csaddr = SWAB32(usb1->fs_csaddr);
+	uspi->s_cssize = SWAB32(usb1->fs_cssize);
+	uspi->s_cgsize = SWAB32(usb1->fs_cgsize);
+	uspi->s_ntrak = SWAB32(usb1->fs_ntrak);
+	uspi->s_nsect = SWAB32(usb1->fs_nsect);
+	uspi->s_spc = SWAB32(usb1->fs_spc);
+	uspi->s_ipg = SWAB32(usb1->fs_ipg);
+	uspi->s_fpg = SWAB32(usb1->fs_fpg);
+	uspi->s_cpc = SWAB32(usb2->fs_cpc);
+        ((u32 *)&tmp)[0] = usb3->fs_u.fs_sun.fs_qbmask[0];
+        ((u32 *)&tmp)[1] = usb3->fs_u.fs_sun.fs_qbmask[1];
+	uspi->s_qbmask = SWAB64(tmp);
+        ((u32 *)&tmp)[0] = usb3->fs_u.fs_sun.fs_qfmask[0];
+        ((u32 *)&tmp)[1] = usb3->fs_u.fs_sun.fs_qfmask[1];
+	uspi->s_qfmask = SWAB64(tmp);
+	uspi->s_postblformat = SWAB32(usb3->fs_postblformat);
+	uspi->s_nrpos = SWAB32(usb3->fs_nrpos);
+	uspi->s_postbloff = SWAB32(usb3->fs_postbloff);
+	uspi->s_rotbloff = SWAB32(usb3->fs_rotbloff);
+
+	/*
+	 * Compute another fraquently used values
+	 */
+	uspi->s_fpbmask = uspi->s_fpb - 1;
+	uspi->s_apbshift = uspi->s_bshift - 2;
+	uspi->s_2apbshift = uspi->s_apbshift * 2;
+	uspi->s_3apbshift = uspi->s_apbshift * 3;
+	uspi->s_apb = 1 << uspi->s_apbshift;
+	uspi->s_2apb = 1 << uspi->s_2apbshift;
+	uspi->s_3apb = 1 << uspi->s_3apbshift;
+	uspi->s_apbmask = uspi->s_apb - 1;
+ 	uspi->s_nspfshift = uspi->s_fshift - SECTOR_BITS;
+	uspi->s_nspb = uspi->s_nspf << uspi->s_fpbshift;
+	uspi->s_inopf = uspi->s_inopb >> uspi->s_fpbshift;
+		
+	sb->u.ufs_sb.s_flags = flags;
+	sb->u.ufs_sb.s_swab = swab;
+	sb->u.ufs_sb.s_rename_lock = 0;
+	sb->u.ufs_sb.s_rename_wait = NULL;
+         	                                                          
+	sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL);
+
+	/*
+	 * Read cs structures from (usually) first data block
+	 * on the device. 
+	 */
+	size = uspi->s_cssize;
+	blks = howmany(size, uspi->s_fsize);
+	base = space = kmalloc(size, GFP_KERNEL);
+	if (!base)
+		goto failed; 
+	for (i = 0; i < blks; i += uspi->s_fpb) {
+		size = uspi->s_bsize;
+		if (i + uspi->s_fpb > blks)
+			size = (blks - i) * uspi->s_fsize;
+		ubh = ubh_bread(sb->s_dev, uspi->s_csaddr + i, size);
+		if (!ubh)
+			goto failed;
+		ubh_ubhcpymem (space, ubh, size);
+		sb->u.ufs_sb.s_csp[ufs_fragstoblks(i)] = (struct ufs_csum *)space;
+		space += size;
+		ubh_brelse (ubh);
+		ubh = NULL;
+	}
+
+	/*
+	 * Read cylinder group (we read only first fragment from block
+	 * at this time) and prepare internal data structures for cg caching.
+	 */
+	if (!(sb->u.ufs_sb.s_ucg = kmalloc (sizeof(struct buffer_head *) * uspi->s_ncg, GFP_KERNEL)))
+		goto failed;
+	for (i = 0; i < uspi->s_ncg; i++) 
+		sb->u.ufs_sb.s_ucg[i] = NULL;
+	for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
+		sb->u.ufs_sb.s_ucpi[i] = NULL;
+		sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY;
+	}
+	for (i = 0; i < uspi->s_ncg; i++) {
+		UFSD(("read cg %u\n", i))
+		if (!(sb->u.ufs_sb.s_ucg[i] = bread (sb->s_dev, ufs_cgcmin(i), sb->s_blocksize)))
+			goto failed;
+		if (!ufs_cg_chkmagic ((struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data))
+			goto failed;
+#ifdef UFS_SUPER_DEBUG_MORE
+		ufs_print_cylinder_stuff((struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data, swab);
+#endif
+	}
+	for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
+		if (!(sb->u.ufs_sb.s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL)))
+			goto failed;
+		sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY;
+	}
+	sb->u.ufs_sb.s_cg_loaded = 0;
+
+	unlock_super(sb);
+	UFSD(("EXIT\n"))
+	return(sb);
+
+failed:
+	if (ubh) ubh_brelse2 (ubh);
+	if (uspi) kfree (uspi);
+	if (base) kfree (base);
+
+	if (sb->u.ufs_sb.s_ucg) {
+		for (i = 0; i < uspi->s_ncg; i++)
+			if (sb->u.ufs_sb.s_ucg[i]) brelse (sb->u.ufs_sb.s_ucg[i]);
+		kfree (sb->u.ufs_sb.s_ucg);
+		for (i = 0; i < UFS_MAX_GROUP_LOADED; i++)
+			if (sb->u.ufs_sb.s_ucpi[i]) kfree (sb->u.ufs_sb.s_ucpi[i]);
+	}
+	sb->s_dev = 0;
+	unlock_super (sb);
+	MOD_DEC_USE_COUNT;
+	UFSD(("EXIT (FAILED)\n"))
+	return(NULL);
+}
+
+/*
+ * Put super block, release internal structures
+ */
+void ufs_put_super (struct super_block * sb)
+{
+	struct ufs_sb_private_info * uspi;
+	struct ufs_buffer_head * ubh;
+	unsigned char * base, * space;
+	unsigned size, blks, i;
+	
+	UFSD(("ENTER\n"))
+	
+	uspi = sb->u.ufs_sb.s_uspi;
+	size = uspi->s_cssize;
+	blks = howmany(size, uspi->s_fsize);
+	base = space = (char*) sb->u.ufs_sb.s_csp[0];
+	for (i = 0; i < blks; i += uspi->s_fpb) {
+		size = uspi->s_bsize;
+		if (i + uspi->s_fpb > blks)
+			size = (blks - i) * uspi->s_fsize;
+		ubh = ubh_bread (sb->s_dev, uspi->s_csaddr + i, size);
+		if (!ubh)
+			goto go_on;
+		ubh_memcpyubh (ubh, space, size);
+		space += size;
+		ubh_mark_buffer_uptodate (ubh, 1);
+		ubh_mark_buffer_dirty (ubh, 0);
+		ubh_brelse (ubh);
+	}
+
+go_on:
+	for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
+		ufs_put_cylinder (sb, i);
+		kfree (sb->u.ufs_sb.s_ucpi[i]);
+	}
+	for (i = 0; i < uspi->s_ncg; i++) 
+		brelse (sb->u.ufs_sb.s_ucg[i]);
+	kfree (sb->u.ufs_sb.s_ucg);
+	kfree (base);
+	ubh_brelse2 (USPI_UBH);
+	kfree (sb->u.ufs_sb.s_uspi);
+	sb->s_dev = 0;
+	MOD_DEC_USE_COUNT;
+	return;
+}
+
+/*
+ * Write super block to device
+ */
+void ufs_write_super (struct super_block * sb) {
+	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block_first * usb1;
+	struct ufs_super_block_third * usb3;
+	unsigned swab;
+	
+	UFSD(("ENTER\n"))
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+	usb1 = ubh_get_usb_first(USPI_UBH);
+	usb3 = ubh_get_usb_third(USPI_UBH);
+	
+	if (!(sb->s_flags & MS_RDONLY)) {
+		if (SWAB16(usb3->fs_u.fs_sun.fs_state) & UFS_FSOK)
+			usb3->fs_u.fs_sun.fs_state = SWAB16(SWAB16(usb3->fs_u.fs_sun.fs_state) & ~UFS_FSOK);
+		usb1->fs_time = SWAB32(CURRENT_TIME);
+		usb3->fs_u.fs_sun.fs_state = SWAB32(UFS_FSOK - SWAB32(usb1->fs_time));
+		ubh_mark_buffer_dirty (USPI_UBH, 1);
+	}
+	sb->s_dirt = 0;
+	UFSD(("EXIT\n"))
+}
+
+/*
+ * Copy some info about file system to user
+ */
+int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz)
+{
+	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block_first * usb1;
+	struct statfs tmp;
+	struct statfs *sp = &tmp;
+	unsigned long used, avail;
+	unsigned swab;
+	
+	UFSD(("ENTER\n"))
+	
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+	usb1 = ubh_get_usb_first (USPI_UBH);
+
+	sp->f_type = UFS_MAGIC;
+	sp->f_bsize = sb->s_blocksize;
+	sp->f_blocks = uspi->s_dsize;
+	sp->f_bfree = (SWAB32(usb1->fs_cstotal.cs_nbfree) << uspi->s_fpbshift )+
+		SWAB32(usb1->fs_cstotal.cs_nffree);
+
+	avail = sp->f_blocks - (sp->f_blocks / 100) * uspi->s_minfree;
+	used = sp->f_blocks - sp->f_bfree;
+	if (avail > used)
+		sp->f_bavail = avail - used;
+	else
+		sp->f_bavail = 0;
+	sp->f_files = uspi->s_ncg * uspi->s_ipg;
+	sp->f_ffree = SWAB32(usb1->fs_cstotal.cs_nifree);
+	sp->f_fsid.val[0] = SWAB32(usb1->fs_id[0]);
+	sp->f_fsid.val[1] = SWAB32(usb1->fs_id[1]);
+	sp->f_namelen = UFS_MAXNAMLEN;
+	
+	UFSD(("EXIT\n"))
+
+	return copy_to_user(buf, sp, bufsiz) ? -EFAULT : 0;
+}
+
+
+static char error_buf[1024];
+
+void ufs_warning (struct super_block * sb, const char * function,
+	const char * fmt, ...)
+{
+	va_list args;
+
+	va_start (args, fmt);
+	vsprintf (error_buf, fmt, args);
+	va_end (args);
+	printk (KERN_WARNING "UFS-fs warning (device %s): %s: %s\n",
+		kdevname(sb->s_dev), function, error_buf);
+}
+
+void ufs_error (struct super_block * sb, const char * function,
+	const char * fmt, ...)
+{
+	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block_first * usb1;
+	va_list args;
+
+	uspi = sb->u.ufs_sb.s_uspi;
+	usb1 = ubh_get_usb_first(USPI_UBH);
+	
+	if (!(sb->s_flags & MS_RDONLY)) {
+		usb1->fs_clean = UFS_FSBAD;
+		ubh_mark_buffer_dirty(USPI_UBH, 1);
+		sb->s_dirt = 1;
+		sb->s_flags |= MS_RDONLY;
+	}
+	va_start (args, fmt);
+	vsprintf (error_buf, fmt, args);
+	va_end (args);
+	printk (KERN_CRIT "UFS-fs error (device %s): %s: %s\n",
+		kdevname(sb->s_dev), function, error_buf);
+}
+
+void ufs_panic (struct super_block * sb, const char * function,
+	const char * fmt, ...)
+{
+	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block_first * usb1;
+	va_list args;
+	
+	uspi = sb->u.ufs_sb.s_uspi;
+	usb1 = ubh_get_usb_first(USPI_UBH);
+	
+	if (!(sb->s_flags & MS_RDONLY)) {
+		usb1->fs_clean = UFS_FSBAD;
+		ubh_mark_buffer_dirty(USPI_UBH, 1);
+		sb->s_dirt = 1;
+	}
+	va_start (args, fmt);
+	vsprintf (error_buf, fmt, args);
+	va_end (args);
+	/* this is to prevent panic from syncing this filesystem */
+	if (sb->s_lock)
+		sb->s_lock = 0;
+	sb->s_flags |= MS_RDONLY;
+	printk (KERN_CRIT "UFS-fs panic (device %s): %s: %s\n",
+		kdevname(sb->s_dev), function, error_buf);
+/*	panic ("UFS-fs panic (device %s): %s: %s\n", 
+		kdevname(sb->s_dev), function, error_buf);
+*/
+}
+
+
+static struct super_operations ufs_super_ops = {
+	ufs_read_inode,
+	ufs_write_inode,
+	ufs_put_inode,
+	ufs_delete_inode,
+	NULL,			/* notify_change() */
+	ufs_put_super,
+	ufs_write_super,
+	ufs_statfs,
+	NULL,			/* XXX - ufs_remount() */
+};
+
+static struct file_system_type ufs_fs_type = {
+	"ufs",
+	FS_REQUIRES_DEV,
+	ufs_read_super,
+	NULL
+};
+
+
+int init_ufs_fs(void)
+{
+	return(register_filesystem(&ufs_fs_type));
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+	return init_ufs_fs();
+}
+
+void cleanup_module(void)
+{
+	unregister_filesystem(&ufs_fs_type);
+}
+#endif
+
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/swab.h linux/fs/ufs/swab.h
--- v2.1.111/linux/fs/ufs/swab.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/ufs/swab.h	Sun Jul 26 01:20:22 1998
@@ -0,0 +1,114 @@
+/*
+ *  linux/fs/ufs/ufs_swab.h
+ *
+ * Copyright (C) 1997 Francois-Rene Rideau <rideau@ens.fr>
+ * Copyright (C) 1998 Jakub Jelinek <jj@ultra.linux.cz>
+ */
+
+#ifndef _UFS_SWAB_H
+#define _UFS_SWAB_H
+
+/*
+ * Notes:
+ *    HERE WE ASSUME EITHER BIG OR LITTLE ENDIAN UFSes
+ *    in case there are ufs implementations that have strange bytesexes,
+ *    you'll need to modify code here as well as in ufs_super.c and ufs_fs.h
+ *    to support them.
+ */
+
+#include <linux/ufs_fs.h>
+#include <asm/byteorder.h>
+
+/*
+ * These are only valid inside ufs routines,
+ * after swab has been initialized to sb->u.ufs_sb.s_swab
+ */
+#define SWAB16(x) ufs_swab16(swab,x)
+#define SWAB32(x) ufs_swab32(swab,x)
+#define SWAB64(x) ufs_swab64(swab,x)
+
+/*
+ * We often use swabing, when we want to increment/decrement some value, so these
+ * macros might become handy and increase readability. (Daniel)
+ */
+#define INC_SWAB16(x)	x=ufs_swab16_add(swab,x,1)
+#define INC_SWAB32(x)	x=ufs_swab32_add(swab,x,1)
+#define INC_SWAB64(x)	x=ufs_swab64_add(swab,x,1)
+#define DEC_SWAB16(x)	x=ufs_swab16_add(swab,x,-1)
+#define DEC_SWAB32(x)	x=ufs_swab32_add(swab,x,-1)
+#define DEC_SWAB64(x)	x=ufs_swab64_add(swab,x,-1)
+#define ADD_SWAB16(x,y)	x=ufs_swab16_add(swab,x,y)
+#define ADD_SWAB32(x,y)	x=ufs_swab32_add(swab,x,y)
+#define ADD_SWAB64(x,y)	x=ufs_swab64_add(swab,x,y)
+#define SUB_SWAB16(x,y)	x=ufs_swab16_add(swab,x,-(y))
+#define SUB_SWAB32(x,y)	x=ufs_swab32_add(swab,x,-(y))
+#define SUB_SWAB64(x,y)	x=ufs_swab64_add(swab,x,-(y))
+
+#ifndef __PDP_ENDIAN
+extern __inline__ __const__ __u16 ufs_swab16(unsigned swab, __u16 x) {
+	if (swab)
+		return swab16(x);
+	else
+		return x;
+}
+extern __inline__ __const__ __u32 ufs_swab32(unsigned swab, __u32 x) {
+	if (swab)
+		return swab32(x);
+	else
+		return x;
+}
+extern __inline__ __const__ __u64 ufs_swab64(unsigned swab, __u64 x) {
+	if (swab)
+		return swab64(x);
+	else
+		return x;
+}
+extern __inline__ __const__ __u16 ufs_swab16_add(unsigned swab, __u16 x, __u16 y) {
+	if (swab)
+		return swab16(swab16(x)+y);
+	else
+		return x + y;
+}
+extern __inline__ __const__ __u32 ufs_swab32_add(unsigned swab, __u32 x, __u32 y) {
+	if (swab)
+		return swab32(swab32(x)+y);
+	else
+		return x + y;
+}
+extern __inline__ __const__ __u64 ufs_swab64_add(unsigned swab, __u64 x, __u64 y) {
+	if (swab)
+		return swab64(swab64(x)+y);
+	else
+		return x + y;
+}
+#else /* __PDP_ENDIAN */
+extern __inline__ __const__ __u16 ufs_swab16(unsigned swab, __u16 x) {
+	if (swab & UFS_LITTLE_ENDIAN)
+		return le16_to_cpu(x);
+	else
+		return be16_to_cpu(x);
+}
+extern __inline__ __const__ __u32 ufs_swab32(unsigned swab, __u32 x) {
+	if (swab & UFS_LITTLE_ENDIAN)
+		return le32_to_cpu(x);
+	else
+		return be32_to_cpu(x);
+}
+extern __inline__ __const__ __u64 ufs_swab64(unsigned swab, __u64 x) {
+	if (swab & UFS_LITTLE_ENDIAN)
+		return le64_to_cpu(x);
+	else
+		return be64_to_cpu(x);
+}
+extern __inline__ __const__ __u16 ufs_swab16_add(unsigned swab, __u16 x, __u16 y) {
+	return ufs_swab16(swab, ufs_swab16(swab, x) + y);
+}
+extern __inline__ __const__ __u32 ufs_swab32_add(unsigned swab, __u32 x, __u32 y) {
+	return ufs_swab32(swab, ufs_swab32(swab, x) + y);
+}
+extern __inline__ __const__ __u64 ufs_swab64_add(unsigned swab, __u64 x, __u64 y) {
+	return ufs_swab64(swab, ufs_swab64(swab, x) + y);
+}
+#endif /* __PDP_ENDIAN */
+
+#endif /* _UFS_SWAB_H */
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/symlink.c linux/fs/ufs/symlink.c
--- v2.1.111/linux/fs/ufs/symlink.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/ufs/symlink.c	Sun Jul 26 01:20:22 1998
@@ -0,0 +1,138 @@
+/*
+ *  linux/ufs/ufs/symlink.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@emai.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ *
+ *  from
+ *
+ *  linux/fs/ext2/symlink.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/fs/minix/symlink.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  ext2 symlink handling code
+ */
+
+#include <asm/uaccess.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/stat.h>
+
+
+#undef UFS_SYMLINK_DEBUG
+
+#ifdef UFS_SYMLINK_DEBUG
+#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+
+static struct dentry * ufs_follow_link(struct dentry * dentry,
+	struct dentry * base)
+{
+	struct inode * inode;
+	struct buffer_head * bh;
+	int error;
+	char * link;
+
+	UFSD(("ENTER\n"))
+
+	inode = dentry->d_inode;
+	bh = NULL;
+	/* slow symlink */	    
+	if (inode->i_blocks) {
+		if (!(bh = ufs_bread (inode, 0, 0, &error))) {
+			dput(base);
+			return ERR_PTR(-EIO);
+		}
+		link = bh->b_data;
+	}
+	/* fast symlink */
+	else {
+		link = (char *) inode->u.ufs_i.i_u1.i_symlink;
+	}
+	UPDATE_ATIME(inode);
+	base = lookup_dentry(link, base, 1);
+	if (bh)
+		brelse(bh);
+	UFSD(("EXIT\n"))
+	return base;
+}
+
+static int ufs_readlink (struct dentry * dentry, char * buffer, int buflen)
+{
+	struct super_block * sb;
+	struct inode * inode;
+	struct buffer_head * bh;
+	char * link;
+	int i;
+
+	UFSD(("ENTER\n"))
+
+	inode = dentry->d_inode;
+	sb = inode->i_sb;
+	bh = NULL;
+	if (buflen > sb->s_blocksize - 1)
+		buflen = sb->s_blocksize - 1;
+	/* slow symlink */
+	if (inode->i_blocks) {
+		int err;
+		bh = ufs_bread (inode, 0, 0, &err);
+		if (!bh) {
+			if(err < 0) /* indicate type of error */
+				return err;
+			return 0;
+		}
+		link = bh->b_data;
+	}
+	/* fast symlink */
+	else {
+		link = (char *) inode->u.ufs_i.i_u1.i_symlink;
+	}
+	i = 0;
+	while (i < buflen && link[i])
+		i++;
+	if (copy_to_user(buffer, link, i))
+		i = -EFAULT;
+ 	UPDATE_ATIME(inode);
+	if (bh)
+		brelse (bh);
+	UFSD(("ENTER\n"))
+	return i;
+}
+
+struct inode_operations ufs_symlink_inode_operations = {
+	NULL,			/* no file-operations */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	ufs_readlink,		/* readlink */
+	ufs_follow_link,	/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL,			/* permission */
+	NULL			/* smap */
+};
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/truncate.c linux/fs/ufs/truncate.c
--- v2.1.111/linux/fs/ufs/truncate.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/ufs/truncate.c	Sun Jul 26 23:30:27 1998
@@ -0,0 +1,473 @@
+/*
+ *  linux/fs/ufs/truncate.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles Uiversity, Faculty of Mathematics and Physics
+ *
+ *  from
+ *
+ *  linux/fs/ext2/truncate.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/fs/minix/truncate.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+
+/*
+ * Real random numbers for secure rm added 94/02/18
+ * Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr>
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ufs_fs.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/locks.h>
+#include <linux/string.h>
+
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_TRUNCATE_DEBUG
+
+#ifdef UFS_TRUNCATE_DEBUG
+#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+ 
+/*
+ * Secure deletion currently doesn't work. It interacts very badly
+ * with buffers shared with memory mappings, and for that reason
+ * can't be done in the truncate() routines. It should instead be
+ * done separately in "release()" before calling the truncate routines
+ * that will release the actual file blocks.
+ *
+ *		Linus
+ */
+
+#define DIRECT_BLOCK howmany (inode->i_size, uspi->s_bsize)
+#define DIRECT_FRAGMENT howmany (inode->i_size, uspi->s_fsize)
+
+static int ufs_trunc_direct (struct inode * inode)
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct buffer_head * bh;
+	u32 * p;
+   	unsigned frag1, frag2, frag3, frag4, block1, block2;
+	unsigned frag_to_free, free_count;
+	unsigned i, j, tmp;
+	int retry;
+	unsigned swab;
+	
+	UFSD(("ENTER\n"))
+
+	sb = inode->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+	
+	frag_to_free = 0;
+	free_count = 0;
+	retry = 0;
+	
+	frag1 = DIRECT_FRAGMENT;
+	frag4 = min (UFS_NDIR_FRAGMENT, inode->u.ufs_i.i_lastfrag);
+	frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1);
+	frag3 = frag4 & ~uspi->s_fpbmask;
+	block1 = block2 = 0;
+	if (frag2 > frag3) {
+		frag2 = frag4;
+		frag3 = frag4 = 0;
+	}
+	else if (frag2 < frag3) {
+		block1 = ufs_fragstoblks (frag2);
+		block2 = ufs_fragstoblks (frag3);
+	}
+
+	UFSD(("frag1 %u, frag2 %u, block1 %u, block2 %u, frag3 %u, frag4 %u\n", frag1, frag2, block1, block2, frag3, frag4))
+
+	if (frag1 >= frag2)
+		goto next1;		
+
+	/*
+	 * Free first free fragments
+	 */
+	p = inode->u.ufs_i.i_u1.i_data + ufs_fragstoblks (frag1);
+	tmp = SWAB32(*p);
+	if (!tmp )
+		ufs_panic (sb, "ufs_trunc_direct", "internal error");
+	frag1 = ufs_fragnum (frag1);
+	frag2 = ufs_fragnum (frag2);
+	for (j = frag1; j < frag2; j++) {
+		bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize);
+		if ((bh && bh->b_count != 1) || tmp != SWAB32(*p)) {
+			retry = 1;
+			brelse (bh);
+			goto next1;
+		}
+		bforget (bh);
+	}
+	inode->i_blocks -= (frag2-frag1) << uspi->s_nspfshift;
+	mark_inode_dirty(inode);
+	ufs_free_fragments (inode, tmp + frag1, frag2 - frag1);
+	frag_to_free = tmp + frag1;
+
+next1:
+	/*
+	 * Free whole blocks
+	 */
+	for (i = block1 ; i < block2; i++) {
+		p = inode->u.ufs_i.i_u1.i_data + i;
+		tmp = SWAB32(*p);
+		if (!tmp)
+			continue;
+		for (j = 0; j < uspi->s_fpb; j++) {
+			bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize);
+			if ((bh && bh->b_count != 1) || tmp != SWAB32(*p)) {
+				retry = 1;
+				brelse (bh);
+				goto next2;
+			}
+			bforget (bh);
+		}
+		*p = SWAB32(0);
+		inode->i_blocks -= uspi->s_nspb;
+		mark_inode_dirty(inode);
+		if (free_count == 0) {
+			frag_to_free = tmp;
+			free_count = uspi->s_fpb;
+		} else if (free_count > 0 && frag_to_free == tmp - free_count)
+			free_count += uspi->s_fpb;
+		else {
+			ufs_free_blocks (inode, frag_to_free, free_count);
+			frag_to_free = tmp;
+			free_count = uspi->s_fpb;
+		}
+next2:
+	}
+	
+	if (free_count > 0)
+		ufs_free_blocks (inode, frag_to_free, free_count);
+
+	if (frag3 >= frag4)
+		goto next3;
+
+	/*
+	 * Free last free fragments
+	 */
+	p = inode->u.ufs_i.i_u1.i_data + ufs_fragstoblks (frag3);
+	tmp = SWAB32(*p);
+	if (!tmp )
+		ufs_panic(sb, "ufs_truncate_direct", "internal error");
+	frag4 = ufs_fragnum (frag4);
+	for (j = 0; j < frag4; j++) {
+		bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize);
+		if ((bh && bh->b_count != 1) || tmp != SWAB32(*p)) {
+			retry = 1;
+			brelse (bh);
+			goto next1;
+		}
+		bforget (bh);
+	}
+	*p = SWAB32(0);
+	inode->i_blocks -= frag4 << uspi->s_nspfshift;
+	mark_inode_dirty(inode);
+	ufs_free_fragments (inode, tmp, frag4);
+ next3:
+
+	UFSD(("EXIT\n"))
+	return retry;
+}
+
+
+static int ufs_trunc_indirect (struct inode * inode, unsigned offset, u32 * p)
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct ufs_buffer_head * ind_ubh;
+	struct buffer_head * bh;
+	u32 * ind;
+	unsigned indirect_block, i, j, tmp;
+	unsigned frag_to_free, free_count;
+	int retry;
+	unsigned swab;
+
+	UFSD(("ENTER\n"))
+		
+	sb = inode->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+
+	frag_to_free = 0;
+	free_count = 0;
+	retry = 0;
+	
+	tmp = SWAB32(*p);
+	if (!tmp)
+		return 0;
+	ind_ubh = ubh_bread (sb->s_dev, tmp, uspi->s_bsize);
+	if (tmp != SWAB32(*p)) {
+		ubh_brelse (ind_ubh);
+		return 1;
+	}
+	if (!ind_ubh) {
+		*p = SWAB32(0);
+		return 0;
+	}
+
+	indirect_block = (DIRECT_BLOCK > offset) ? (DIRECT_BLOCK - offset) : 0;
+	for (i = indirect_block; i < uspi->s_apb; i++) {
+		ind = ubh_get_addr32 (ind_ubh, i);
+		tmp = SWAB32(*ind);
+		if (!tmp)
+			continue;
+		for (j = 0; j < uspi->s_fpb; j++) {
+			bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize);
+			if ((bh && bh->b_count != 1) || tmp != SWAB32(*ind)) {
+				retry = 1;
+				brelse (bh);
+				goto next;
+			}
+			bforget (bh);
+		}	
+		*ind = SWAB32(0);
+		ubh_mark_buffer_dirty(ind_ubh, 1);
+		if (free_count == 0) {
+			frag_to_free = tmp;
+			free_count = uspi->s_fpb;
+		} else if (free_count > 0 && frag_to_free == tmp - free_count)
+			free_count += uspi->s_fpb;
+		else {
+			ufs_free_blocks (inode, frag_to_free, free_count);
+			frag_to_free = tmp;
+			free_count = uspi->s_fpb;
+		}
+		inode->i_blocks -= uspi->s_nspb;
+		mark_inode_dirty(inode);
+next:
+	}
+
+	if (free_count > 0) {
+		ufs_free_blocks (inode, frag_to_free, free_count);
+	}
+	for (i = 0; i < uspi->s_apb; i++)
+		if (SWAB32(*ubh_get_addr32(ind_ubh,i)))
+			break;
+	if (i >= uspi->s_apb) {
+		if (ubh_max_bcount(ind_ubh) != 1) {
+			retry = 1;
+		}
+		else {
+			tmp = SWAB32(*p);
+			*p = SWAB32(0);
+			inode->i_blocks -= uspi->s_nspb;
+			mark_inode_dirty(inode);
+			ufs_free_blocks (inode, tmp, uspi->s_fpb);
+			ubh_bforget(ind_ubh);
+			ind_ubh = NULL;
+		}
+	}
+	if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) {
+		ubh_ll_rw_block (WRITE, 1, &ind_ubh);
+		ubh_wait_on_buffer (ind_ubh);
+	}
+	ubh_brelse (ind_ubh);
+	
+	UFSD(("EXIT\n"))
+	
+	return retry;
+}
+
+static int ufs_trunc_dindirect (struct inode * inode, unsigned offset, u32 * p)
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct ufs_buffer_head * dind_bh;
+	unsigned i, tmp, dindirect_block;
+	u32 * dind;
+	int retry = 0;
+	unsigned swab;
+	
+	UFSD(("ENTER\n"))
+	
+	sb = inode->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+
+	dindirect_block = (DIRECT_BLOCK > offset) 
+		? ((DIRECT_BLOCK - offset) / uspi->s_apb) : 0;
+	retry = 0;
+	
+	tmp = SWAB32(*p);
+	if (!tmp)
+		return 0;
+	dind_bh = ubh_bread (inode->i_dev, tmp, uspi->s_bsize);
+	if (tmp != SWAB32(*p)) {
+		ubh_brelse (dind_bh);
+		return 1;
+	}
+	if (!dind_bh) {
+		*p = SWAB32(0);
+		return 0;
+	}
+
+	for (i = dindirect_block ; i < uspi->s_apb ; i++) {
+		dind = ubh_get_addr32 (dind_bh, i);
+		tmp = SWAB32(*dind);
+		if (!tmp)
+			continue;
+		retry |= ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind);
+		ubh_mark_buffer_dirty(dind_bh, 1);
+	}
+
+	for (i = 0; i < uspi->s_apb; i++)
+		if (SWAB32(*ubh_get_addr32 (dind_bh, i)))
+			break;
+	if (i >= uspi->s_apb) {
+		if (ubh_max_bcount(dind_bh) != 1)
+			retry = 1;
+		else {
+			tmp = SWAB32(*p);
+			*p = SWAB32(0);
+			inode->i_blocks -= uspi->s_nspb;
+			mark_inode_dirty(inode);
+			ufs_free_blocks (inode, tmp, uspi->s_fpb);
+			ubh_bforget(dind_bh);
+			dind_bh = NULL;
+		}
+	}
+	if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) {
+		ubh_ll_rw_block (WRITE, 1, &dind_bh);
+		ubh_wait_on_buffer (dind_bh);
+	}
+	ubh_brelse (dind_bh);
+	
+	UFSD(("EXIT\n"))
+	
+	return retry;
+}
+
+static int ufs_trunc_tindirect (struct inode * inode)
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct ufs_buffer_head * tind_bh;
+	unsigned tindirect_block, tmp, i;
+	u32 * tind, * p;
+	int retry;
+	unsigned swab;
+	
+	UFSD(("ENTER\n"))
+
+	sb = inode->i_sb;
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+	retry = 0;
+	
+	tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb))
+		? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) / uspi->s_2apb) : 0;
+	p = inode->u.ufs_i.i_u1.i_data + UFS_TIND_BLOCK;
+	if (!(tmp = SWAB32(*p)))
+		return 0;
+	tind_bh = ubh_bread (sb->s_dev, tmp, uspi->s_bsize);
+	if (tmp != SWAB32(*p)) {
+		ubh_brelse (tind_bh);
+		return 1;
+	}
+	if (!tind_bh) {
+		*p = SWAB32(0);
+		return 0;
+	}
+
+	for (i = tindirect_block ; i < uspi->s_apb ; i++) {
+		tind = ubh_get_addr32 (tind_bh, i);
+		retry |= ufs_trunc_dindirect(inode, UFS_NDADDR + 
+			uspi->s_apb + ((i + 1) << uspi->s_2apbshift), tind);
+		ubh_mark_buffer_dirty(tind_bh, 1);
+	}
+	for (i = 0; i < uspi->s_apb; i++)
+		if (SWAB32(*ubh_get_addr32 (tind_bh, i)))
+			break;
+	if (i >= uspi->s_apb) {
+		if (ubh_max_bcount(tind_bh) != 1)
+			retry = 1;
+		else {
+			tmp = SWAB32(*p);
+			*p = SWAB32(0);
+			inode->i_blocks -= uspi->s_nspb;
+			mark_inode_dirty(inode);
+			ufs_free_blocks (inode, tmp, uspi->s_fpb);
+			ubh_bforget(tind_bh);
+			tind_bh = NULL;
+		}
+	}
+	if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) {
+		ubh_ll_rw_block (WRITE, 1, &tind_bh);
+		ubh_wait_on_buffer (tind_bh);
+	}
+	ubh_brelse (tind_bh);
+	
+	UFSD(("EXIT\n"))
+	return retry;
+}
+		
+void ufs_truncate (struct inode * inode)
+{
+	struct super_block * sb;
+	struct ufs_sb_private_info * uspi;
+	struct buffer_head * bh;
+	unsigned offset;
+	int err, retry;
+	
+	UFSD(("ENTER\n"))
+	sb = inode->i_sb;
+	uspi = sb->u.ufs_sb.s_uspi;
+
+	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)))
+		return;
+	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+		return;
+	while (1) {
+		retry = ufs_trunc_direct(inode);
+		retry |= ufs_trunc_indirect (inode, UFS_IND_BLOCK,
+			(u32 *) &inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK]);
+		retry |= ufs_trunc_dindirect (inode, UFS_IND_BLOCK + uspi->s_apb,
+			(u32 *) &inode->u.ufs_i.i_u1.i_data[UFS_DIND_BLOCK]);
+		retry |= ufs_trunc_tindirect (inode);
+		if (!retry)
+			break;
+		if (IS_SYNC(inode) && (inode->i_state & I_DIRTY))
+			ufs_sync_inode (inode);
+		current->counter = 0;
+		schedule ();
+
+
+	}
+	offset = inode->i_size & uspi->s_fshift;
+	if (offset) {
+		bh = ufs_bread (inode, inode->i_size >> uspi->s_fshift, 0, &err);
+		if (bh) {
+			memset (bh->b_data + offset, 0, uspi->s_fsize - offset);
+			mark_buffer_dirty (bh, 0);
+			brelse (bh);
+		}
+	}
+	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	inode->u.ufs_i.i_lastfrag = howmany (inode->i_size, uspi->s_fsize);
+	mark_inode_dirty(inode);
+	UFSD(("EXIT\n"))
+}
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ufs_dir.c linux/fs/ufs/ufs_dir.c
--- v2.1.111/linux/fs/ufs/ufs_dir.c	Tue Feb 17 13:12:48 1998
+++ linux/fs/ufs/ufs_dir.c	Wed Dec 31 16:00:00 1969
@@ -1,191 +0,0 @@
-/*
- *  linux/fs/ufs/ufs_dir.c
- *
- * Copyright (C) 1996
- * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
- * Laboratory for Computer Science Research Computing Facility
- * Rutgers, The State University of New Jersey
- *
- * swab support by Francois-Rene Rideau <rideau@ens.fr> 19970406
- *
- * 4.4BSD (FreeBSD) support added on February 1st 1998 by
- * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
- * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
- */
-
-#include <linux/fs.h>
-
-#include "ufs_swab.h"
-
-/*
- * This is blatantly stolen from ext2fs
- */
-static int
-ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
-{
-	struct inode *inode = filp->f_dentry->d_inode;
-	int error = 0;
-	unsigned long offset, lblk, blk;
-	int i, stored;
-	struct buffer_head * bh;
-	struct ufs_direct * de;
-	struct super_block * sb;
-	int de_reclen;
-	__u32 flags;
-
-	/* Isn't that already done in the upper layer???
-         * the VFS layer really needs some explicit documentation!
-         */
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return -EBADF;
-
-	sb = inode->i_sb;
-        flags = sb->u.ufs_sb.s_flags;
-
-	if (flags & UFS_DEBUG) {
-	        printk("ufs_readdir: ino %lu  f_pos %lu\n",
-	               inode->i_ino, (unsigned long) filp->f_pos);
-	        ufs_print_inode(inode);
-	}
-
-	stored = 0;
-	bh = NULL;
-	offset = filp->f_pos & (sb->s_blocksize - 1);
-
-	while (!error && !stored && filp->f_pos < inode->i_size) {
-		lblk = (filp->f_pos) >> sb->s_blocksize_bits;
-	        /* XXX - ufs_bmap() call needs error checking */
-	        blk = ufs_bmap(inode, lblk);
-		bh = bread (sb->s_dev, blk, sb->s_blocksize);
-		if (!bh) {
-	                /* XXX - error - skip to the next block */
-	                printk("ufs_readdir: "
-			       "dir inode %lu has a hole at offset %lu\n",
-	                       inode->i_ino, (unsigned long int)filp->f_pos);
-			filp->f_pos += sb->s_blocksize - offset;
-			continue;
-		}
-
-revalidate:
-		/* If the dir block has changed since the last call to
-		 * readdir(2), then we might be pointing to an invalid
-		 * dirent right now.  Scan from the start of the block
-		 * to make sure. */
-		if (filp->f_version != inode->i_version) {
-			for (i = 0; i < sb->s_blocksize && i < offset; ) {
-				de = (struct ufs_direct *)
-					(bh->b_data + i);
-				/* It's too expensive to do a full
-				 * dirent test each time round this
-				 * loop, but we do have to test at
-				 * least that it is non-zero.  A
-				 * failure will be detected in the
-				 * dirent test below. */
-				de_reclen = SWAB16(de->d_reclen);
-				if (de_reclen < 1)
-					break;
-				i += de_reclen;
-			}
-			offset = i;
-			filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
-				| offset;
-			filp->f_version = inode->i_version;
-		}
-
-		while (!error && filp->f_pos < inode->i_size
-		       && offset < sb->s_blocksize) {
-			de = (struct ufs_direct *) (bh->b_data + offset);
-	                /* XXX - put in a real ufs_check_dir_entry() */
-	                if ((de->d_reclen == 0) || (NAMLEN(de) == 0)) {
-			/* SWAB16() was unneeded -- compare to 0 */
-	                        filp->f_pos = (filp->f_pos &
-				              (sb->s_blocksize - 1)) +
-				               sb->s_blocksize;
-	                        brelse(bh);
-	                        return stored;
-	                }
-#if 0 /* XXX */
-			if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
-			/* XXX - beware about de having to be swabped somehow */
-						   bh, offset)) {
-				/* On error, skip the f_pos to the
-	                           next block. */
-				filp->f_pos = (filp->f_pos &
-				              (sb->s_blocksize - 1)) +
-					       sb->s_blocksize;
-				brelse (bh);
-				return stored;
-			}
-#endif /* XXX */
-			offset += SWAB16(de->d_reclen);
-			if (de->d_ino) {
-			/* SWAB16() was unneeded -- compare to 0 */
-				/* We might block in the next section
-				 * if the data destination is
-				 * currently swapped out.  So, use a
-				 * version stamp to detect whether or
-				 * not the directory has been modified
-				 * during the copy operation. */
-				unsigned long version = inode->i_version;
-
-	                        if (flags & UFS_DEBUG) {
-	                                printk("ufs_readdir: filldir(%s,%u)\n",
-	                                       de->d_name, SWAB32(de->d_ino));
-	                        }
-				error = filldir(dirent, de->d_name, NAMLEN(de),
-				                filp->f_pos, SWAB32(de->d_ino));
-				if (error)
-					break;
-				if (version != inode->i_version)
-					goto revalidate;
-				stored ++;
-			}
-			filp->f_pos += SWAB16(de->d_reclen);
-		}
-		offset = 0;
-		brelse (bh);
-	}
-#if 0 /* XXX */
-	if (!IS_RDONLY(inode)) {
-		inode->i_atime = CURRENT_TIME;
-		inode->i_dirt = 1;
-	}
-#endif /* XXX */
-	return 0;
-}
-
-static struct file_operations ufs_dir_operations = {
-	NULL,			/* lseek */
-	NULL,			/* read */
-	NULL,			/* write */
-	ufs_readdir,		/* readdir */
-	NULL,			/* select */
-	NULL,			/* ioctl */
-	NULL,			/* mmap */
-	NULL,			/* open */
-	NULL,			/* release */
-	file_fsync,		/* fsync */
-	NULL,			/* fasync */
-	NULL,			/* check_media_change */
-	NULL,			/* revalidate */
-};
-
-struct inode_operations ufs_dir_inode_operations = {
-	&ufs_dir_operations,	/* default directory file operations */
-	NULL,			/* create */
-	ufs_lookup,		/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	NULL,			/* readlink */
-	NULL,			/* readpage */
-	NULL,			/* writepage */
-	NULL,			/* bmap */
-	NULL,			/* truncate */
-	NULL,			/* permission */
-	NULL,			/* smap */
-};
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ufs_file.c linux/fs/ufs/ufs_file.c
--- v2.1.111/linux/fs/ufs/ufs_file.c	Tue Oct 21 05:26:13 1997
+++ linux/fs/ufs/ufs_file.c	Wed Dec 31 16:00:00 1969
@@ -1,52 +0,0 @@
-/*
- *  linux/fs/ufs/ufs_file.c
- *
- * Copyright (C) 1996
- * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
- * Laboratory for Computer Science Research Computing Facility
- * Rutgers, The State University of New Jersey
- *
- * $Id: ufs_file.c,v 1.9 1997/07/17 02:24:13 davem Exp $
- *
- */
-
-#include <linux/fs.h>
-#include <linux/ufs_fs.h>
-
-static struct file_operations ufs_file_operations = {
-	NULL,			/* lseek */
-	generic_file_read,	/* read */
-	NULL,			/* write */
-	NULL,			/* readdir */
-	NULL,			/* select */
-	NULL,			/* ioctl */
-	generic_file_mmap,	/* mmap */
-	NULL,			/* open */
-	NULL,			/* release */
-	file_fsync,		/* fsync */
-	NULL,			/* fasync */
-	NULL,			/* check_media_change */
-	NULL,			/* revalidate */
-};
-
-struct inode_operations ufs_file_inode_operations = {
-	&ufs_file_operations,	/* default directory file operations */
-	NULL,			/* create */
-	NULL,			/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	NULL,			/* readlink */
-	NULL,			/* follow_link */
-	generic_readpage,	/* readpage */
-	NULL,			/* writepage */
-	ufs_bmap,		/* bmap */
-	NULL,			/* truncate */
-	NULL,			/* permission */
-	NULL,			/* smap */
-};
-
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ufs_inode.c linux/fs/ufs/ufs_inode.c
--- v2.1.111/linux/fs/ufs/ufs_inode.c	Wed Jun 24 22:54:10 1998
+++ linux/fs/ufs/ufs_inode.c	Wed Dec 31 16:00:00 1969
@@ -1,334 +0,0 @@
-/*
- *  linux/fs/ufs/ufs_inode.c
- *
- * Copyright (C) 1996
- * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
- * Laboratory for Computer Science Research Computing Facility
- * Rutgers, The State University of New Jersey
- *
- * Clean swab support on 19970406
- * by Francois-Rene Rideau <rideau@ens.fr>
- *
- * 4.4BSD (FreeBSD) support added on February 1st 1998 by
- * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
- * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
- *
- * NeXTstep support added on February 5th 1998 by
- * Niels Kristian Bech Jensen <nkbj@image.dk>.
- */
-
-#undef DEBUG_UFS_INODE
-/*#define DEBUG_UFS_INODE 1*/
-/* Uncomment the line above when hacking ufs inode code */
-
-#include <linux/fs.h>
-#include <linux/ufs_fs.h>
-#include <linux/sched.h>
-
-#include "ufs_swab.h"
-
-void ufs_print_inode(struct inode * inode)
-{
-	printk("ino %lu  mode 0%6.6o  lk %d  uid %d  gid %d"
-	       "  sz %lu  blks %lu  cnt %u\n",
-	       inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid,
-	       inode->i_gid, inode->i_size, inode->i_blocks, inode->i_count);
-	printk("  db <0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x"
-	       " 0x%x 0x%x 0x%x 0x%x>\n",
-		inode->u.ufs_i.i_u1.i_data[0], inode->u.ufs_i.i_u1.i_data[1],
-		inode->u.ufs_i.i_u1.i_data[2], inode->u.ufs_i.i_u1.i_data[3],
-		inode->u.ufs_i.i_u1.i_data[4], inode->u.ufs_i.i_u1.i_data[5],
-		inode->u.ufs_i.i_u1.i_data[6], inode->u.ufs_i.i_u1.i_data[7],
-		inode->u.ufs_i.i_u1.i_data[8], inode->u.ufs_i.i_u1.i_data[9],
-		inode->u.ufs_i.i_u1.i_data[10], inode->u.ufs_i.i_u1.i_data[11]);
-	printk("  gen 0x%8.8x ib <0x%x 0x%x 0x%x>\n",
-		inode->u.ufs_i.i_gen,
-		inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK],
-		inode->u.ufs_i.i_u1.i_data[UFS_DIND_BLOCK],
-		inode->u.ufs_i.i_u1.i_data[UFS_TIND_BLOCK]);
-}
-
-#define inode_bmap(inode, nr) ((inode)->u.ufs_i.i_u1.i_data[(nr)])
-
-static inline int block_bmap (struct inode *inode, int block, int nr)
-{
-	struct buffer_head *bh;
-	int tmp;
-	__u32 flags = inode->i_sb->u.ufs_sb.s_flags;
-	/* XXX Split in fsize big blocks (Can't bread 8Kb). */ 
-	tmp = nr >> (inode->i_sb->u.ufs_sb.s_fshift - 2);
-	bh = bread (inode->i_dev, inode->i_sb->u.ufs_sb.s_blockbase + block +
-	            tmp, inode->i_sb->s_blocksize);
-	if (!bh)
-		return 0;
-	nr &= ~(inode->i_sb->u.ufs_sb.s_fmask) >> 2;
-	tmp = SWAB32(((__u32 *)bh->b_data)[nr]);
-	brelse (bh);
-	return tmp;
-}
-
-int ufs_bmap (struct inode * inode, int block)
-{
-	int i;
-	int addr_per_block = UFS_ADDR_PER_BLOCK(inode->i_sb);
-	int addr_per_block_bits = UFS_ADDR_PER_BLOCK_BITS(inode->i_sb);
-	int lbn = ufs_lbn (inode->i_sb, block);
-	int boff = ufs_boff (inode->i_sb, block);
-
-	if (lbn < 0) {
-		ufs_warning (inode->i_sb, "ufs_bmap", "block < 0");
-		return 0;
-	}
-	if (lbn >= UFS_NDADDR + addr_per_block +
-		(1 << (addr_per_block_bits * 2)) +
-		((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
-		ufs_warning (inode->i_sb, "ufs_bmap", "block > big");
-		return 0;
-	}
-	if (lbn < UFS_NDADDR)
-		return (inode->i_sb->u.ufs_sb.s_blockbase +
-			ufs_dbn (inode->i_sb, inode_bmap (inode, lbn), boff));
-	lbn -= UFS_NDADDR;
-	if (lbn < addr_per_block) {
-		i = inode_bmap (inode, UFS_IND_BLOCK);
-		if (!i)
-			return 0;
-		return (inode->i_sb->u.ufs_sb.s_blockbase +
-			ufs_dbn (inode->i_sb,
-				block_bmap (inode, i, lbn), boff));
-	}
-	lbn -= addr_per_block;
-	if (lbn < (1 << (addr_per_block_bits * 2))) {
-		i = inode_bmap (inode, UFS_DIND_BLOCK);
-		if (!i)
-			return 0;
-		i = block_bmap (inode, i, lbn >> addr_per_block_bits);
-		if (!i)
-			return 0;
-		return (inode->i_sb->u.ufs_sb.s_blockbase +
-			ufs_dbn (inode->i_sb,
-				block_bmap (inode, i, lbn & (addr_per_block-1)),
-				boff));
-	}
-	lbn -= (1 << (addr_per_block_bits * 2));
-	i = inode_bmap (inode, UFS_TIND_BLOCK);
-	if (!i)
-		return 0;
-	i = block_bmap (inode, i, lbn >> (addr_per_block_bits * 2));
-	if (!i)
-		return 0;
-	i = block_bmap (inode, i,
-			(lbn >> addr_per_block_bits) & (addr_per_block - 1));
-	if (!i)
-		return 0;
-	return (inode->i_sb->u.ufs_sb.s_blockbase +
-		ufs_dbn (inode->i_sb,
-			block_bmap (inode, i, lbn & (addr_per_block-1)), boff));
-}
-
-/* XXX - ufs_read_inode is a mess */
-void ufs_read_inode(struct inode * inode)
-{
-	struct super_block * sb;
-	struct ufs_inode * ufsip;
-	struct buffer_head * bh;
-	__u32 flags = inode->i_sb->u.ufs_sb.s_flags;
-
-	sb = inode->i_sb;
-
-	if (ufs_ino_ok(inode)) {
-	        printk("ufs_read_inode: bad inum %lu\n", inode->i_ino);
-
-	        return;
-	}
-
-#ifdef DEBUG_UFS_INODE
-	printk("ufs_read_inode: ino %lu  cg %u  cgino %u  ipg %u  inopb %u\n",
-	       inode->i_ino, ufs_ino2cg(inode),
-	       (inode->i_ino%sb->u.ufs_sb.s_inopb),
-	       sb->u.ufs_sb.s_ipg, sb->u.ufs_sb.s_inopb);
-#endif
-	bh = bread(inode->i_dev,
-	           inode->i_sb->u.ufs_sb.s_blockbase +
-	           ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) +
-	           (inode->i_ino%sb->u.ufs_sb.s_ipg)/
-	           (sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag),
-	           sb->s_blocksize);
-	if (!bh) {
-	        printk("ufs_read_inode: can't read inode %lu from dev %d/%d\n",
-	               inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
-	        return;
-	}
-
-	ufsip = (struct ufs_inode *)bh->b_data;
-	ufsip += (inode->i_ino%(sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag));
-
-	/*
-	 * Copy data to the in-core inode.
-	 */
-	inode->i_mode = SWAB16(ufsip->ui_mode);
-	inode->i_nlink = SWAB16(ufsip->ui_nlink);
-	if (inode->i_nlink == 0) {
-	        /* XXX */
-	        printk("ufs_read_inode: zero nlink ino %lu  dev %u/%u\n",
-	               inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
-	        inode->i_nlink = 1;
-	        printk("ufs_read_inode: fishy ino %lu pblk %lu dev %u/%u\n",
-	               inode->i_ino,
-	               ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) +
-	               (inode->i_ino%sb->u.ufs_sb.s_ipg)/sb->u.ufs_sb.s_inopb,
-	               MAJOR(inode->i_dev), MINOR(inode->i_dev));
-	}
-	/* XXX - debugging */
-	if (SWAB32(ufsip->ui_gen) == 0) {
-	        printk("ufs_read_inode: zero gen ino %lu pblk %lu dev %u/%u\n",
-	               inode->i_ino,
-	               ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) +
-	               (inode->i_ino%sb->u.ufs_sb.s_ipg)/sb->u.ufs_sb.s_inopb,
-	               MAJOR(inode->i_dev), MINOR(inode->i_dev));
-	}
-	/*
-	 * Since Linux currently only has 16-bit uid_t and gid_t, we can't
-	 * really support EFTs.  For the moment, we use 0 as the uid and gid
-	 * if an inode has a uid or gid that won't fit in 16 bits.  This way
-	 * random users can't get at these files, since they get dynamically
-	 * "chown()ed" to root.
-	 */
-	if (UFS_UID(ufsip) >= UFS_USEEFT) {
-	        inode->i_uid = 0;
-	        printk("ufs_read_inode: EFT uid %u ino %lu dev %u/%u, using %u\n",
-	               UFS_UID(ufsip), inode->i_ino, MAJOR(inode->i_dev),
-	               MINOR(inode->i_dev), inode->i_uid);
-	} else {
-	        inode->i_uid = UFS_UID(ufsip);
-	}
-	if (UFS_GID(ufsip) >= UFS_USEEFT) {
-	        inode->i_gid = 0;
-	        printk("ufs_read_inode: EFT gid %u ino %lu dev %u/%u, using %u\n",
-	               UFS_GID(ufsip), inode->i_ino, MAJOR(inode->i_dev),
-	               MINOR(inode->i_dev), inode->i_gid);
-	} else {
-	        inode->i_gid = UFS_GID(ufsip);
-	}
-
-	/*
-	 * Linux i_size is 32 bits on most architectures,
-	 * so some files on a UFS filesystem may not
-	 * be readable.  I let people access the first 32 bits worth of them.
-	 * for the rw code, we may want to mark these inodes as read-only.
-	 * XXX - bug Linus to make i_size a __u64 instead of a __u32.
-	 */
-	inode->u.ufs_i.i_size = SWAB64(ufsip->ui_size);
-	/* KRR - Just type cast inode->u.ufs_i.i_size into off_t and
-	 * worry about overflow later
-         */
-	inode->i_size = (off_t)inode->u.ufs_i.i_size;
-
-	/*
-	 * Linux doesn't keep tv_usec around in the kernel, so we discard it.
-	 * XXX - I'm not sure what I should do about writing things.  I may
-	 * want to keep this data, but for the moment I think I'll just write
-	 * zeros for these fields when writing out inodes.
-	 */
-	inode->i_atime = SWAB32(ufsip->ui_atime.tv_sec);
-	inode->i_mtime = SWAB32(ufsip->ui_mtime.tv_sec);
-	inode->i_ctime = SWAB32(ufsip->ui_ctime.tv_sec);
-	inode->i_blksize = sb->u.ufs_sb.s_fsize;
-	inode->i_blocks = SWAB32(ufsip->ui_blocks);
-	inode->i_version = ++event; /* see linux/kernel/sched.c */
-
-	if (S_ISREG(inode->i_mode)) {
-	        inode->i_op = &ufs_file_inode_operations;
-	} else if (S_ISDIR(inode->i_mode)) {
-	        inode->i_op = &ufs_dir_inode_operations;
-	} else if (S_ISLNK(inode->i_mode)) {
-	        inode->i_op = &ufs_symlink_inode_operations;
-	} else if (S_ISCHR(inode->i_mode)) {
-	        inode->i_op = &chrdev_inode_operations;
-	} else if (S_ISBLK(inode->i_mode)) {
-	        inode->i_op = &blkdev_inode_operations;
-	} else if (S_ISFIFO(inode->i_mode)) {
-	        init_fifo(inode);
-	} else if (S_ISSOCK(inode->i_mode)) {
-		/* nothing */
-	} else {
-	        printk("ufs_read_inode: unknown file type 0%o ino %lu dev %d/%d\n",
-	               inode->i_mode, inode->i_ino, MAJOR(inode->i_dev),
-	               MINOR(inode->i_dev));
-	        /* XXX - debugging */
-	        ufs_print_inode(inode);
-	        inode->i_op = &ufs_file_inode_operations;
-	}
-
-	/*
-	 * ufs_read_super makes sure that UFS_NDADDR and UFS_NINDIR are sane.
-	 */
-	if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
-	    S_ISLNK(inode->i_mode)) {
-	        int i;
-
-		if (inode->i_blocks) {
-		        for (i = 0; i < UFS_NDADDR; i++) {
-		                inode->u.ufs_i.i_u1.i_data[i] =
-				       SWAB32(ufsip->ui_u2.ui_addr.ui_db[i]);
-		        }
-		        for (i = 0; i < UFS_NINDIR; i++) {
-		                inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK + i] =
-				       SWAB32(ufsip->ui_u2.ui_addr.ui_ib[i]);
-	        	}
-		} else /* fast symlink */ {
-			memcpy(inode->u.ufs_i.i_u1.i_symlink,
-			       ufsip->ui_u2.ui_symlink, 60);
-		}
-	}
-
-	/* KRR - I need to check the SunOS header files, but for the time
-	 * being, I'm going to tread ui_db[0] and [1] as a __u64 and swab
-	 * them appropriately.  This should clean up any real endian problems,
-	 * but we'll still need to add size checks in the write portion of
-	 * the code.
-	 */
-	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
-	  inode->i_rdev = (kdev_t)SWAB64(*(__u64*)&ufsip->ui_u2.ui_addr.ui_db);
-	}
-
-	inode->u.ufs_i.i_flags = SWAB32(ufsip->ui_flags);
-	inode->u.ufs_i.i_gen = SWAB32(ufsip->ui_gen); /* XXX - is this i_version? */
-	inode->u.ufs_i.i_shadow = SWAB32(ufsip->ui_u3.ui_sun.ui_shadow); /* XXX */
-	inode->u.ufs_i.i_uid = SWAB32(ufsip->ui_u3.ui_sun.ui_uid);
-	inode->u.ufs_i.i_gid = SWAB32(ufsip->ui_u3.ui_sun.ui_gid);
-	inode->u.ufs_i.i_oeftflag = SWAB32(ufsip->ui_u3.ui_sun.ui_oeftflag);
-
-	brelse(bh);
-
-	if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_INODE)) {
-	        ufs_print_inode(inode);
-	}
-
-	return;
-}
-
-void ufs_put_inode (struct inode * inode)
-{
-	if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_INODE)) {
-		printk("ufs_put_inode:\n");
-	        ufs_print_inode(inode);
-	}
-
-	if (inode->i_nlink)
-	        return;
-
-	printk("ufs_put_inode: nlink == 0 for inum %lu on dev %d/%d\n",
-	       inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
-	ufs_print_inode(inode);
-	panic("ufs_put_inode: fs is read only, and nlink == 0");
-
-	/* XXX - this code goes here eventually
-	inode->i_size = 0;
-	if (inode->i_blocks)
-	        ufs_truncate(inode);
-	ufs_free_inode(inode);
-	*/
-
-	return;
-}
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ufs_namei.c linux/fs/ufs/ufs_namei.c
--- v2.1.111/linux/fs/ufs/ufs_namei.c	Tue Feb 17 13:12:48 1998
+++ linux/fs/ufs/ufs_namei.c	Wed Dec 31 16:00:00 1969
@@ -1,195 +0,0 @@
-/*
- *  linux/fs/ufs/ufs_namei.c
- *
- * Copyright (C) 1996
- * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
- * Laboratory for Computer Science Research Computing Facility
- * Rutgers, The State University of New Jersey
- *
- * Clean swab support by Francois-Rene Rideau <rideau@ens.fr> 19970406
- * Ported to 2.1.62 by Francois-Rene Rideau <rideau@ens.fr> 19971109
- *
- * 4.4BSD (FreeBSD) support added on February 1st 1998 by
- * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
- * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
- */
-
-#include <linux/fs.h>
-#include <linux/ufs_fs.h>
-#include <linux/string.h>
-#include "ufs_swab.h"
-
-/*
- * NOTE1: unlike strncmp, ufs_match returns 1 for success, 0 for failure
- * (stolen from ext2fs.)
- * NOTE2: flags *is* used, though this is hidden by macros like NAMLEN.
- */
-static int ufs_match (int len, const char * const name, struct ufs_direct * d, __u32 flags)
-{
-	if (!d || len > UFS_MAXNAMLEN) /* XXX - name space */
-		return 0;
-	/*
-	 * "" means "." ---> so paths like "/usr/lib//libc.a" work
-	 */
-	if (!len && (NAMLEN(d) == 1) && (d->d_name[0] == '.') &&
-  	   (d->d_name[1] == '\0'))
-  		return 1;
-	if (len != NAMLEN(d))
-		return 0;
-	return !memcmp(name, d->d_name, len);
-}
-
-int ufs_lookup (struct inode *dir, struct dentry *dentry)
-{
-  /* XXX - this is all fucked up! */
-	unsigned long int lfragno, fragno;
-	struct buffer_head * bh;
-	struct ufs_direct * d;
-	struct super_block * sb = dir->i_sb;
-	const char *name = dentry->d_name.name;
-	int len = dentry->d_name.len;
-	__u32 flags;
-        struct inode *inode;
-
-	/* XXX - isn't that already done by the upper layer? */
-        if (!dir || !S_ISDIR(dir->i_mode))
-		return -EBADF;
-
-	flags = sb->u.ufs_sb.s_flags;
-
-	if (flags & UFS_DEBUG)
-		printk("Passed name: %s\nPassed length: %d\n", name, len);
-
-	/* debugging hacks:
-	 * Touching /xyzzy in a filesystem toggles debugging messages.
-	 */
-	if ((len == 5) && !(memcmp(name, "xyzzy", len)) &&
-	    (dir->i_ino == UFS_ROOTINO)) {
-	        sb->u.ufs_sb.s_flags ^= UFS_DEBUG;
-	        printk("UFS debugging %s\n",
-	               (sb->u.ufs_sb.s_flags & UFS_DEBUG) ?
-	               "on": "off");
-		goto not_found;
-	        /*return(-ENOENT);*/
-	}
-
-	/*
-	 * Touching /xyzzy.i in a filesystem toggles debugging for ufs_inode.c
-	 */
-	if ((len == 7) && !(memcmp(name, "xyzzy.i", len)) &&
-	    (dir->i_ino == UFS_ROOTINO)) {
-	        sb->u.ufs_sb.s_flags ^= UFS_DEBUG_INODE;
-	        printk("UFS inode debugging %s\n",
-	               (sb->u.ufs_sb.s_flags & UFS_DEBUG_INODE) ?
-	               "on": "off");
-		goto not_found;
-	        /*return(-ENOENT);*/
-	}
-
-	/*
-	 * Touching /xyzzy.n in a filesystem toggles debugging for ufs_namei.c
-	 */
-	if ((len == 7) && !(memcmp(name, "xyzzy.n", len)) &&
-	    (dir->i_ino == UFS_ROOTINO)) {
-	        sb->u.ufs_sb.s_flags ^= UFS_DEBUG_NAMEI;
-	        printk("UFS namei debugging %s\n",
-	               (sb->u.ufs_sb.s_flags & UFS_DEBUG_NAMEI) ?
-	               "on": "off");
-		goto not_found;
-	        /*return(-ENOENT);*/
-	}
-
-	/*
-	 * Touching /xyzzy.l in a filesystem toggles debugging for ufs_symlink.c
-	 */
-	if ((len == 7) && !(memcmp(name, "xyzzy.l", len)) &&
-	    (dir->i_ino == UFS_ROOTINO)) {
-	        sb->u.ufs_sb.s_flags ^= UFS_DEBUG_LINKS;
-	        printk("UFS symlink debugging %s\n",
-	               (sb->u.ufs_sb.s_flags & UFS_DEBUG_LINKS) ?
-	               "on": "off");
-		goto not_found;
-	        /*return(-ENOENT);*/
-	}
-
-	/* Now for the real thing */
-
- 	if (flags & (UFS_DEBUG|UFS_DEBUG_NAMEI)) {
-	        printk("ufs_lookup: called for ino %lu  name %s\n",
-	               dir->i_ino, name);
-	}
-
- 	for (lfragno = 0; lfragno < dir->i_blocks; lfragno++) {
-	        fragno = ufs_bmap(dir, lfragno);
- 		/* ufs_bmap() reads the block (frag) size in s_blocksize */
-	        /* XXX - ufs_bmap() call needs error checking */
- 	        if (flags & UFS_DEBUG) {
-	                printk("ufs_lookup: ino %lu lfragno %lu  fragno %lu\n",
-	                       dir->i_ino, lfragno, fragno);
-	        }
-	        if (fragno == 0) {
-	                /* XXX - bug bug bug */
-			goto not_found;
-			/*return(-ENOENT);*/
-	        }
-	        bh = bread(dir->i_dev, fragno, sb->s_blocksize);
-	        if (bh == NULL) {
-	                printk("ufs_lookup: bread failed: "
-                               "ino %lu, lfragno %lu",
-	                       dir->i_ino, lfragno);
-	                return(-EIO);
-	        }
-	        d = (struct ufs_direct *)(bh->b_data);
-	        while (((char *)d - bh->b_data + SWAB16(d->d_reclen)) <=
-	               sb->s_blocksize) {
-	                /* XXX - skip block if d_reclen or d_namlen is 0 */
-	                if ((d->d_reclen == 0) || (NAMLEN(d) == 0)) {
-			/* no need to SWAB16(): test against 0 */
-	                        if (flags & UFS_DEBUG) {
-	                                printk("ufs_lookup: skipped space in directory, ino %lu\n",
-	                                       dir->i_ino);
-	                        }
-	                        break;
-	                }
-	                if (flags & UFS_DEBUG) {
-	                        printk("lfragno 0x%lx  "
-					"direct d 0x%x  "
-					"d_ino %u  "
-					"d_reclen %u  "
-					"d_namlen %u  d_name `%s'\n",
-	                        	lfragno,
-				        (unsigned int)((unsigned long)d),
-					SWAB32(d->d_ino),
-					SWAB16(d->d_reclen),
-					NAMLEN(d),d->d_name);
-	                }
-	                if ((NAMLEN(d) == len) &&
-	                    /* XXX - don't use strncmp() - see ext2fs */
-	                    (ufs_match(len, name, d, flags))) {
-	                        /* We have a match */
-/* XXX - I only superficially understand how things work,
- * so use at your own risk... -- Fare'
- */
-				inode = iget(sb, SWAB32(d->d_ino));
-				brelse(bh);
-				if(!inode) { return -EACCES; }
-                                d_add(dentry,inode);
-	                        return(0);
-	                } else {
-	                        /* XXX - bounds checking */
-	                        if (flags & UFS_DEBUG) {
-	                                printk("ufs_lookup: "
-						"wanted (%s,%d) got (%s,%d)\n",
-	                                       name, len,
-					       d->d_name, NAMLEN(d));
-	                        }
-	                }
-			d = (struct ufs_direct *)((char *)d +
-			     SWAB16(d->d_reclen));
-	        }
-	        brelse(bh);
-	}
-   not_found:
-	d_add(dentry,NULL);
-	return(0);
-}
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ufs_super.c linux/fs/ufs/ufs_super.c
--- v2.1.111/linux/fs/ufs/ufs_super.c	Mon Apr  6 17:41:01 1998
+++ linux/fs/ufs/ufs_super.c	Wed Dec 31 16:00:00 1969
@@ -1,384 +0,0 @@
-/*
- *  linux/fs/ufs/ufs_super.c
- *
- * Copyright (C) 1996
- * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
- * Laboratory for Computer Science Research Computing Facility
- * Rutgers, The State University of New Jersey
- *
- * Copyright (C) 1996  Eddie C. Dost  (ecd@skynet.be)
- *
- */
-
-/*
- * Kernel module support added on 96/04/26 by
- * Stefan Reinauer <stepan@home.culture.mipt.ru>
- *
- * Module usage counts added on 96/04/29 by
- * Gertjan van Wingerde <gertjan@cs.vu.nl>
- *
- * Clean swab support on 19970406 by
- * Francois-Rene Rideau <rideau@ens.fr>
- *
- * 4.4BSD (FreeBSD) support added on February 1st 1998 by
- * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
- * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
- *
- * NeXTstep support added on February 5th 1998 by
- * Niels Kristian Bech Jensen <nkbj@image.dk>.
- */
-
-#undef DEBUG_UFS_SUPER
-/*#define DEBUG_UFS_SUPER 1*/
-/* Uncomment the line above when hacking ufs superblock code */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/ufs_fs.h>
-#include <linux/locks.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-
-#include "ufs_swab.h"
-
-struct super_block * ufs_read_super(struct super_block * sb, void * data, int silent);
-void ufs_put_super (struct super_block * sb);
-int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsize);
-
-static struct super_operations ufs_super_ops = {
-	ufs_read_inode,
-	NULL,			/* XXX - ufs_write_inode() */
-	ufs_put_inode,
-	NULL,			/* XXX - ufs_delete_inode() */
-	NULL,			/* XXX - notify_change() */
-	ufs_put_super,
-	NULL,			/* XXX - ufs_write_super() */
-	ufs_statfs,
-	NULL,			/* XXX - ufs_remount() */
-};
-
-static struct file_system_type ufs_fs_type = {
-	"ufs",
-	FS_REQUIRES_DEV,
-	ufs_read_super,
-	NULL
-};
-
-__initfunc(int init_ufs_fs(void))
-{
-	return(register_filesystem(&ufs_fs_type));
-}
-
-#ifdef MODULE
-EXPORT_NO_SYMBOLS;
-
-int init_module(void)
-{
-	return init_ufs_fs();
-}
-
-void cleanup_module(void)
-{
-	unregister_filesystem(&ufs_fs_type);
-}
-#endif
-
-static char error_buf[1024];
-
-void ufs_warning (struct super_block * sb, const char * function,
-		  const char * fmt, ...)
-{
-	va_list args;
-
-	va_start (args, fmt);
-	vsprintf (error_buf, fmt, args);
-	va_end (args);
-	printk (KERN_WARNING "UFS warning (device %s): %s: %s\n",
-		kdevname(sb->s_dev), function, error_buf);
-}
-
-#ifdef DEBUG_UFS_SUPER
-static void
-ufs_print_super_stuff(struct super_block * sb, struct ufs_superblock * usb)
-{
-	__u32 flags = sb->u.ufs_sb.s_flags;
-
-	printk("fs_sblkno: 0x%8.8x\n", usb->fs_sblkno);
-	printk("fs_size:   0x%8.8x\n", usb->fs_size);
-	printk("fs_ncg:    0x%8.8x\n", usb->fs_ncg);
-	printk("fs_bsize:  0x%8.8x\n", usb->fs_bsize);
-	printk("fs_fsize:  0x%8.8x\n", usb->fs_fsize);
-	printk("fs_frag:   0x%8.8x\n", usb->fs_frag);
-	printk("fs_nindir: 0x%8.8x\n", usb->fs_nindir);
-	printk("fs_inopb:  0x%8.8x\n", usb->fs_inopb);
-	printk("fs_optim:  0x%8.8x\n", usb->fs_optim);
-	printk("fs_ncyl:   0x%8.8x\n", usb->fs_ncyl);
-	printk("fs_clean:  0x%8.8x\n", usb->fs_clean);
-	printk("fs_state:  0x%8.8x\n", UFS_STATE(usb));
-	printk("fs_magic:  0x%8.8x\n", usb->fs_magic);
-	printk("fs_fsmnt:  `%s'\n", usb->fs_fsmnt);
-
-	return;
-}
-#endif
-
-struct super_block *
-ufs_read_super(struct super_block * sb, void * data, int silent)
-{
-	struct ufs_superblock * usb;	/* normalized to local byteorder */
-	struct buffer_head * bh1, *bh2;
-	__u32 flags = UFS_DEBUG_INITIAL; /* for sb->u.ufs_sb.s_flags */
-	static int offsets[] = { 0, 96, 160 };	/* different superblock locations */
-	int i;
-
-	/* sb->s_dev and sb->s_flags are set by our caller
-	 * data is the mystery argument to sys_mount()
-	 *
-	 * Our caller also sets s_dev, s_covered, s_rd_only, s_dirt,
-	 *   and s_type when we return.
-	 */
-
-	MOD_INC_USE_COUNT;
-	lock_super (sb);
-	set_blocksize (sb->s_dev, BLOCK_SIZE);
-
-	/* XXX - make everything read only for testing */
-	sb->s_flags |= MS_RDONLY;
-
-	for (i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) {
-		if (!(bh1 = bread(sb->s_dev, offsets[i] + UFS_SBLOCK/BLOCK_SIZE,
-		            BLOCK_SIZE)) ||
-		    !(bh2 = bread(sb->s_dev, offsets[i] +
-		            UFS_SBLOCK/BLOCK_SIZE + 1, BLOCK_SIZE))) {
-			brelse(bh1);
-		        printk ("ufs_read_super: unable to read superblock\n");
-			goto ufs_read_super_lose;
-		}
-		/* XXX - redo this so we can free it later... */
-		usb = (struct ufs_superblock *)__get_free_page(GFP_KERNEL);
-		if (usb == NULL) {
-			brelse(bh1);
-			brelse(bh2);
-		        printk ("ufs_read_super: get_free_page() failed\n");
-			goto ufs_read_super_lose;
-		}
-
-		memcpy((char *)usb, bh1->b_data, BLOCK_SIZE);
-		memcpy((char *)usb + BLOCK_SIZE, bh2->b_data,
-		       sizeof(struct ufs_superblock) - BLOCK_SIZE);
-
-		brelse(bh1);
-		brelse(bh2);
-
-		switch (le32_to_cpup(&usb->fs_magic)) {
-			case UFS_MAGIC:
-				flags |= UFS_LITTLE_ENDIAN;
-				ufs_superblock_le_to_cpus(usb);
-				goto found;
-			case UFS_CIGAM:
-				flags |= UFS_BIG_ENDIAN;
-				ufs_superblock_be_to_cpus(usb);
-				goto found;
-				/* usb is now normalized to local byteorder */
-			default:
-		}
-	}
-	printk ("ufs_read_super: bad magic number 0x%8.8x "
-		"on dev %d/%d\n", usb->fs_magic,
-		MAJOR(sb->s_dev), MINOR(sb->s_dev));
-	goto ufs_read_super_lose;
-found:
-#ifdef DEBUG_UFS_SUPER
-	printk("ufs_read_super: superblock offset 0x%2.2x\n", offsets[i]);
-#endif
-	/* We found a UFS filesystem on this device. */
-
-	/* XXX - parse args */
-
-	if ((usb->fs_bsize != 4096) && (usb->fs_bsize != 8192)) {
-	        printk("ufs_read_super: invalid fs_bsize = %d\n",
-	               usb->fs_bsize);
-	        goto ufs_read_super_lose;
-	}
-
-	if ((usb->fs_fsize != 512) && (usb->fs_fsize != 1024)) {
-	        printk("ufs_read_super: invalid fs_fsize = %d\n",
-	               usb->fs_fsize);
-	        goto ufs_read_super_lose;
-	}
-	if (usb->fs_fsize != BLOCK_SIZE) {
-		set_blocksize (sb->s_dev, usb->fs_fsize);
-	}
-
-	flags |= UFS_VANILLA;
-	/* XXX more consistency check */
-#ifdef DEBUG_UFS_SUPER
-	printk("ufs_read_super: maxsymlinklen 0x%8.8x\n",
-	        usb->fs_u.fs_44.fs_maxsymlinklen);
-#endif
-	if (usb->fs_u.fs_44.fs_maxsymlinklen >= 0) {
-        	if (usb->fs_u.fs_44.fs_inodefmt >= UFS_44INODEFMT) {
-                	flags |= UFS_44BSD;
-                } else {
-                	flags |= UFS_OLD;	/* 4.2BSD */
-                }
-	} else if (offsets[i] > 0) {
-		flags |= UFS_NEXT;
-	} else {
-		flags |= UFS_SUN;
-	}
-
-#ifdef DEBUG_UFS_SUPER
-	ufs_print_super_stuff(sb, usb);
-#endif
-	if (    ((flags&UFS_ST_MASK)==UFS_ST_44BSD)
-             || ((flags&UFS_ST_MASK)==UFS_ST_OLD)
-             || ((flags&UFS_ST_MASK)==UFS_ST_NEXT)
-             || ( ((flags&UFS_ST_MASK)==UFS_ST_SUN)
-                  && UFS_STATE(usb) == UFS_FSOK - usb->fs_time)) {
-		switch(usb->fs_clean) {
-			case UFS_FSACTIVE:	/* 0x00 */
-				printk("ufs_read_super: fs is active\n");
-				sb->s_flags |= MS_RDONLY;
-				break;
-			case UFS_FSCLEAN:	/* 0x01 */
-#ifdef DEBUG_UFS_SUPER
-				printk("ufs_read_super: fs is clean\n");
-#endif
-				break;
-			case UFS_FSSTABLE:	/* 0x02 */
-#ifdef DEBUG_UFS_SUPER
-				printk("ufs_read_super: fs is stable\n");
-#endif
-				break;
-			case UFS_FSOSF1:	/* 0x03 */
-				/* XXX is this correct for DEC OSF/1? */
-#ifdef DEBUG_UFS_SUPER
-				printk("ufs_read_super: fs is clean and stable (OSF/1)\n");
-#endif
-				break;
-			case UFS_FSBAD:		/* 0xFF */
-				printk("ufs_read_super: fs is bad\n");
-				sb->s_flags |= MS_RDONLY;
-				break;
-			default:
-				printk("ufs_read_super: can't grok fs_clean 0x%x\n",
-					usb->fs_clean);
-				sb->s_flags |= MS_RDONLY;
-				break;
-		}
-	} else {
-		printk("ufs_read_super: fs needs fsck\n");
-		sb->s_flags |= MS_RDONLY;
-		/* XXX - make it read only or barf if it's not (/, /usr) */
-	}
-
-	/* XXX - sanity check sb fields */
-
-	/* KRR - Why are we not using fs_bsize for blocksize? */
-	sb->s_blocksize = usb->fs_fsize;
-	sb->s_blocksize_bits = usb->fs_fshift;
-	/* XXX - sb->s_lock */
-	sb->s_op = &ufs_super_ops;
-	sb->dq_op = 0; /* XXX */
-	sb->s_magic = usb->fs_magic;
-	/* sb->s_time */
-	/* sb->s_wait */
-	/* XXX - sb->u.ufs_sb */
-	sb->u.ufs_sb.s_raw_sb = usb; /* XXX - maybe move this to the top */
-	sb->u.ufs_sb.s_flags = flags ;
-	sb->u.ufs_sb.s_ncg = usb->fs_ncg;
-	sb->u.ufs_sb.s_ipg = usb->fs_ipg;
-	sb->u.ufs_sb.s_fpg = usb->fs_fpg;
-	sb->u.ufs_sb.s_fsize = usb->fs_fsize;
-	sb->u.ufs_sb.s_fmask = usb->fs_fmask;
-	sb->u.ufs_sb.s_fshift = usb->fs_fshift;
-	sb->u.ufs_sb.s_bsize = usb->fs_bsize;
-	sb->u.ufs_sb.s_bmask = usb->fs_bmask;
-	sb->u.ufs_sb.s_bshift = usb->fs_bshift;
-	sb->u.ufs_sb.s_iblkno = usb->fs_iblkno;
-	sb->u.ufs_sb.s_dblkno = usb->fs_dblkno;
-	sb->u.ufs_sb.s_cgoffset = usb->fs_cgoffset;
-	sb->u.ufs_sb.s_cgmask = usb->fs_cgmask;
-	sb->u.ufs_sb.s_inopb = usb->fs_inopb;
-	sb->u.ufs_sb.s_lshift = usb->fs_bshift - usb->fs_fshift;
-	sb->u.ufs_sb.s_lmask = ~((usb->fs_fmask - usb->fs_bmask)
-					>> usb->fs_fshift);
-	sb->u.ufs_sb.s_fsfrag = usb->fs_frag; /* XXX - rename this later */
-	sb->u.ufs_sb.s_blockbase = offsets[i];
-	sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL);
-
-#ifdef DEBUG_UFS_SUPER
-	printk("ufs_read_super: inopb %u\n", sb->u.ufs_sb.s_inopb);
-#endif
-	/*
-	 * XXX - read cg structs?
-	 */
-
-	unlock_super(sb);
-	return(sb);
-
-ufs_read_super_lose:
-	/* XXX - clean up */
-	set_blocksize (sb->s_dev, BLOCK_SIZE);
-	sb->s_dev = 0;
-	unlock_super (sb);
-	MOD_DEC_USE_COUNT;
-	return(NULL);
-}
-
-void ufs_put_super (struct super_block * sb)
-{
-        if (sb->u.ufs_sb.s_flags & UFS_DEBUG) {
-		printk("ufs_put_super\n"); /* XXX */
-        }
-
-
-	/* XXX - sync fs data, set state to ok, and flush buffers */
-	set_blocksize (sb->s_dev, BLOCK_SIZE);
-
-	/* XXX - free allocated kernel memory */
-	/* includes freeing usb page */
-
-	MOD_DEC_USE_COUNT;
-
-	return;
-}
-
-int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz)
-{
-	struct statfs tmp;
-	struct statfs *sp = &tmp;
-	struct ufs_superblock *fsb = sb->u.ufs_sb.s_raw_sb;
-	/* fsb was already normalized during mounting */
-	unsigned long used, avail;
-
-        if (sb->u.ufs_sb.s_flags & UFS_DEBUG) {
-		printk("ufs_statfs\n"); /* XXX */
-        }
-
-	sp->f_type = sb->s_magic;
-	sp->f_bsize = sb->s_blocksize;
-	sp->f_blocks = fsb->fs_dsize;
-	sp->f_bfree = fsb->fs_cstotal.cs_nbfree *
-			fsb->fs_frag +
-			fsb->fs_cstotal.cs_nffree;
-
-	avail = sp->f_blocks - (sp->f_blocks / 100) *
-			fsb->fs_minfree;
-	used = sp->f_blocks - sp->f_bfree;
-	if (avail > used)
-		sp->f_bavail = avail - used;
-	else
-		sp->f_bavail = 0;
-
-	sp->f_files = sb->u.ufs_sb.s_ncg * sb->u.ufs_sb.s_ipg;
-	sp->f_ffree = fsb->fs_cstotal.cs_nifree;
-	sp->f_fsid.val[0] = fsb->fs_id[0];
-	sp->f_fsid.val[1] = fsb->fs_id[1];
-	sp->f_namelen = UFS_MAXNAMLEN;
-
-	return copy_to_user(buf, sp, bufsiz) ? -EFAULT : 0;
-}
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ufs_swab.c linux/fs/ufs/ufs_swab.c
--- v2.1.111/linux/fs/ufs/ufs_swab.c	Tue Feb 17 13:12:48 1998
+++ linux/fs/ufs/ufs_swab.c	Wed Dec 31 16:00:00 1969
@@ -1,178 +0,0 @@
-/*
- *  linux/fs/ufs/ufs_swab.c
- *
- * Copyright (C) 1997
- * Francois-Rene Rideau <rideau@ens.fr>
- *
- */
-
-/*
- * For inspiration, you might wanna check sys/ufs/ffs/fs.h from whateverBSD
- *
- * NOTES
- * 19970406 - Fare <rideau@ens.fr>
- *   1) I began from old very preliminary 2.0.x sources,
- *	but it was underfeatured;
- *	I later saw that 2.1.1 sources had a *global* UFS byteswap flag.
- *	EVIL: imagine that a swabbed partition be mounted
- *	while a non-swabbed partition are active (that sucks!)
- *	I merged that source tree with mine.
- *   2) I hope no one is using obNNUUXXIIous byteorder.
- *	That's the only thing I might have broken,
- *	though I rather think it's a fix:
- *	instead of __u64 like BSD,
- *	the former driver used an explicitly bigendian array of __u32!
- *   3) I provide a few macros that use GCC C Extensions.
- *	Port to other compilers would require avoiding them.
- *	in any case, 64 bit (long long) support is required,
- *	unless you're ready to workaround
- *   4) the swab routines below depend on the precise name and order
- *	of the structure elements. Watch out any modification in ufs_fs.h!!!
- *   5) putting byteswapping stuff in ufs_swab* seems cleaner to me.
- *   6) These sources should work with both 2.0 and 2.1 kernels...
- *
- * 19971013 - Fare <rideaufr@issy.cnet.fr>
- *   1) Ported to 2.1.57
- *   2) instead of byteswapping, use [bl]e_to_cpu:
- *     it might be that we run on a VAX!
- *
- * 4.4BSD (FreeBSD) support added on February 1st 1998 by
- * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
- * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
- *
- * HOWTO continue adding swab support:
- *	basically, anywhere metadata is bread() (i.e. mapped to block device),
- *      data should either be SWAB()ed on the fly,
- *      or copied to a buffer and globally bswap_ufs_*() there.
- *
- */
-
-#include <linux/fs.h>
-#include "ufs_swab.h"
-
-static __inline__ void n_be16_to_cpus(__u16*p,unsigned n) {
-#ifndef __BIG_ENDIAN
-        unsigned i;
-        for(i=0;i<n;i++) {
-		be16_to_cpus(&p[i]);
-        }
-#endif
-}
-static __inline__ void n_be32_to_cpus(__u32*p,unsigned n) {
-#ifndef __BIG_ENDIAN
-        unsigned i;
-        for(i=0;i<n;i++) {
-		be32_to_cpus(&p[i]);
-        }
-#endif
-}
-static __inline__ void n_le16_to_cpus(__u16*p,unsigned n) {
-#ifndef __LITTLE_ENDIAN
-        unsigned i;
-        for(i=0;i<n;i++) {
-		le16_to_cpus(&p[i]);
-        }
-#endif
-}
-static __inline__ void n_le32_to_cpus(__u32*p,unsigned n) {
-#ifndef __LITTLE_ENDIAN
-        unsigned i;
-        for(i=0;i<n;i++) {
-		le32_to_cpus(&p[i]);
-        }
-#endif
-}
-
-#define __length_before(p,member) \
-        ((unsigned)(((char*)&((p)->member))-(char*)(p)))
-#define __length_since(p,member) \
-        ((unsigned)(sizeof(*p)-__length_before(p,member)))
-#define __length_between(p,begin,after_end) \
-        ((unsigned)(__length_before(p,after_end)-__length_before(p,begin)))
-#define be32_to_cpus__between(s,begin,after_end) \
-        n_be32_to_cpus((__u32*)&((s).begin), \
-                __length_between(&s,begin,after_end)/4)
-#define le32_to_cpus__between(s,begin,after_end) \
-        n_le32_to_cpus((__u32*)&((s).begin), \
-                __length_between(&s,begin,after_end)/4)
-#define be32_to_cpus__since(s,begin) \
-	n_be32_to_cpus((__u32*)&((s).begin), \
-                __length_since(&s,begin)/4)
-#define le32_to_cpus__since(s,begin) \
-	n_le32_to_cpus((__u32*)&((s).begin), \
-                __length_since(&s,begin)/4)
-#define be16_to_cpus__between(s,begin,after_end) \
-	n_be16_to_cpus((__u16*)&((s).begin), \
-                __length_between(&s,begin,after_end)/2)
-#define le16_to_cpus__between(s,begin,after_end) \
-	n_le16_to_cpus((__u16*)&((s).begin), \
-                __length_between(&s,begin,after_end)/2)
-
-/*
- * Here are the whole-structure swabping routines...
- * They were fun to design, but I don't understand why we
- * need a copy of the superblock, anyway. -- Fare'
- */
-
-extern void ufs_superblock_be_to_cpus(struct ufs_superblock * usb) {
-#ifndef __BIG_ENDIAN
-	__u16 sb_type = 1;	/* SUN type superblock */
-
-	if (usb->fs_u.fs_44.fs_maxsymlinklen >= 0)
-		sb_type = 0;	/* 4.4BSD (FreeBSD) type superblock */
- 
-	be32_to_cpus__between(*usb,fs_link,fs_fmod);
-        /* XXX - I dunno what to do w/ fs_csp,
-         * but it is unused by the current code, so that's ok for now.
-         */
-	be32_to_cpus(&usb->fs_cpc);
-	if (sb_type) {
-        	be16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_sun.fs_sparecon);
-        	be32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_sun.fs_qbmask);
-                /* Might fail on strictly aligning 64-bit big-endian
-                 * architectures. Ouch!
-                 */
-        	be64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qbmask);
-        	be64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qfmask);
-	} else {
-        	be16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_44.fs_sparecon);
-        	be32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_44.fs_maxfilesize);
-        	be64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_maxfilesize);
-        	be64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qbmask);
-        	be64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qfmask);
-        	be32_to_cpus((__s32 *) &usb->fs_u.fs_44.fs_state);
-	}
-	be32_to_cpus__between(*usb,fs_postblformat,fs_magic);
-#endif
-}
-extern void ufs_superblock_le_to_cpus(struct ufs_superblock * usb) {
-#ifndef __LITTLE_ENDIAN
-	__u16 sb_type = 1;	/* SUN type superblock */
-
-	if (usb->fs_u.fs_44.fs_maxsymlinklen >= 0)
-		sb_type = 0;	/* 4.4BSD (FreeBSD) type superblock */
- 
-	le32_to_cpus__between(*usb,fs_link,fs_fmod);
-        /* XXX - I dunno what to do w/ fs_csp,
-         * but it is unused by the current code, so that's ok for now.
-         */
-	le32_to_cpus(&usb->fs_cpc);
-	if (sb_type) {
-        	le16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_sun.fs_sparecon);
-        	le32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_sun.fs_qbmask);
-                /* Might fail on strictly aligning 64-bit big-endian
-                 * architectures. Ouch!
-                 */
-        	le64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qbmask);
-        	le64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qfmask);
-	} else {
-        	le16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_44.fs_sparecon);
-        	le32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_44.fs_maxfilesize);
-        	le64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_maxfilesize);
-        	le64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qbmask);
-        	le64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qfmask);
-        	le32_to_cpus((__s32 *) &usb->fs_u.fs_44.fs_state);
-	}
-	le32_to_cpus__between(*usb,fs_postblformat,fs_magic);
-#endif
-}
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ufs_swab.h linux/fs/ufs/ufs_swab.h
--- v2.1.111/linux/fs/ufs/ufs_swab.h	Tue Feb 17 13:12:48 1998
+++ linux/fs/ufs/ufs_swab.h	Wed Dec 31 16:00:00 1969
@@ -1,121 +0,0 @@
-/*
- *  linux/fs/ufs/ufs_swab.h
- *
- * Copyright (C) 1997 
- * Francois-Rene Rideau <rideau@ens.fr>
- *
- */
-
-#ifndef _UFS_SWAB_H
-#define _UFS_SWAB_H
-
-
-/*
- * Notes:
- * (1) HERE WE ASSUME EITHER BIG OR LITTLE ENDIAN UFSes
- *    in case there are ufs implementations that have strange bytesexes,
- *    you'll need to modify code here as well as in ufs_super.c and ufs_fs.h
- *    to support them.
- * (2) for a read/write ufs driver, we should distinguish
- *    between byteswapping for read or write accesses!
- *    naming should then be UFS16_TO_CPU and suches.
- *
- * 4.4BSD (FreeBSD) support added on February 1st 1998 by
- * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
- * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
- */
-
-#include <linux/ufs_fs.h>
-#include <asm/byteorder.h>
-
-/*
- * These are only valid inside ufs routines, after a variable named flags
- * has been made visible in current scope and properly initialized:
-	__u32 flags = sb->u.ufs_sb.s_flags ;
- */
-#define SWAB16(x) ufs_swab16(flags,x)
-#define SWAB32(x) ufs_swab32(flags,x)
-#define SWAB64(x) ufs_swab64(flags,x)
-
-extern __inline__ __const__ __u16 ufs_swab16(__u32 flags, __u16 x) {
-	if ((flags&UFS_BYTESEX) == UFS_LITTLE_ENDIAN) {
-		return le16_to_cpu(x);
-	} else {
-		return be16_to_cpu(x);
-	}
-}
-extern __inline__ __const__ __u32 ufs_swab32(__u32 flags, __u32 x) {
-	if ((flags&UFS_BYTESEX) == UFS_LITTLE_ENDIAN) {
-		return le32_to_cpu(x);
-	} else {
-		return be32_to_cpu(x);
-	}
-}
-extern __inline__ __const__ __u64 ufs_swab64(__u32 flags, __u64 x) {
-	if ((flags&UFS_BYTESEX) == UFS_LITTLE_ENDIAN) {
-		return le64_to_cpu(x);
-	} else {
-		return be64_to_cpu(x);
-	}
-}
-
-
-/*
- * These are for in-core superblock normalization.
- * It might or not be a bad idea once we go to a read/write driver,
- * as all critical info should be copied to the sb info structure anyway.
- * So better replace them with a static inline function
- * ufs_superblock_to_sb_info() in ufs_super.c
- */
-extern void ufs_superblock_le_to_cpus(struct ufs_superblock * usb);
-extern void ufs_superblock_be_to_cpus(struct ufs_superblock * usb);
-
-
-/*
- * These also implicitly depend on variable flags...
- * NAMLEN(foo) is already normalized to local format, so don't SWAB16() it!
- */
-
-#define NAMLEN(direct) ufs_namlen(flags,direct)
-extern __inline__ __u16 ufs_namlen(__u32 flags, struct ufs_direct * direct) {
-	if ( (flags&UFS_DE_MASK) == UFS_DE_OLD) {
-        	return SWAB16(direct->d_u.d_namlen);
-	} else /* UFS_DE_44BSD */ {
-        	return direct->d_u.d_44.d_namlen;
-	}
-}
-
-/* Here is how the uid is computed:
-   if the file system is 4.2BSD, get it from oldids.
-   if it has sun extension and oldids is USEEFT, get it from ui_sun.
-   if it is 4.4 or Hurd, get it from ui_44 (which is the same as ui_hurd).
-   depends on implicit variable flags being initialized from
-	__u32 flags = sb->u.ufs_sb.s_flags;
-*/
-#define UFS_UID(ino)	ufs_uid(flags,ino)
-#define UFS_GID(ino)	ufs_gid(flags,ino)
-
-extern __inline__ __u32 ufs_uid(__u32 flags,struct ufs_inode * ino) {
-	switch(flags&UFS_UID_MASK) {
-		case UFS_UID_EFT:
-			return SWAB32(ino->ui_u3.ui_sun.ui_uid) ;
-		case UFS_UID_44BSD:
-                  	return SWAB32(ino->ui_u3.ui_44.ui_uid) ;
-		case UFS_UID_OLD:
-		default:
-                	return SWAB16(ino->ui_u1.oldids.suid) ;
-	}
-}
-extern __inline__ __u32 ufs_gid(__u32 flags,struct ufs_inode * ino) {
-	switch(flags&UFS_UID_MASK) {
-		case UFS_UID_EFT:
-			return SWAB32(ino->ui_u3.ui_sun.ui_gid) ;
-		case UFS_UID_44BSD:
-                  	return SWAB32(ino->ui_u3.ui_44.ui_gid) ;
-		case UFS_UID_OLD:
-		default:
-                	return SWAB16(ino->ui_u1.oldids.sgid) ;
-	}
-}
-
-#endif /* _UFS_SWAB_H */
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/ufs_symlink.c linux/fs/ufs/ufs_symlink.c
--- v2.1.111/linux/fs/ufs/ufs_symlink.c	Tue Feb 17 13:12:48 1998
+++ linux/fs/ufs/ufs_symlink.c	Wed Dec 31 16:00:00 1969
@@ -1,146 +0,0 @@
-/*
- *  linux/fs/ufs/ufs_symlink.c
- *
- * Copyright (C) 1996
- * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
- * Laboratory for Computer Science Research Computing Facility
- * Rutgers, The State University of New Jersey
- *
- * Ported to 2.1.62 by Francois-Rene Rideau <rideau@ens.fr> 19971109
- *
- * 4.4BSD (FreeBSD) support added on February 1st 1998 by
- * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
- * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
- */
-
-#include <linux/fs.h>
-#include <linux/ufs_fs.h>
-#include <linux/sched.h>
-
-#include <asm/uaccess.h>
-
-extern int ufs_bmap (struct inode *, int);
-
-static int
-ufs_readlink(struct dentry * dentry, char * buffer, int buflen)
-{
-	struct inode * inode = dentry->d_inode;
-	struct super_block * sb = inode->i_sb;
-	unsigned long int block;
-	struct buffer_head * bh = NULL;
-	char * link;
-	int i;
-	char c;
-
-	if (sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) {
-	        printk("ufs_readlink: called on ino %lu dev %u/%u\n",
-	               inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
-	}
-
-	if (!S_ISLNK(inode->i_mode)) {
-		return -EINVAL;
-	}
-   
-	if (buflen > sb->s_blocksize - 1)
-		buflen = sb->s_blocksize - 1;
-	if (inode->i_blocks) {
-	        /* XXX - error checking */
-	        block = ufs_bmap(inode, 0);
-	        if (sb->u.ufs_sb.s_flags &(UFS_DEBUG|UFS_DEBUG_LINKS)) {
-	                printk("ufs_readlink: bmap got %lu for ino %lu\n",
-	                       block, inode->i_ino);
-		}
-	        bh = bread(inode->i_dev, block, sb->s_blocksize);
-		if (!bh) {
-	                printk("ufs_readlink: can't read block 0 for ino %lu on dev %u/%u\n",
-	                       inode->i_ino, MAJOR(inode->i_dev),
-	                       MINOR(inode->i_dev));
-			return 0;
-		}
-		link = bh->b_data;
-		/* no need to bswap */
-	} else /* fast symlink */ {
-	        link = (char *)&(inode->u.ufs_i.i_u1.i_symlink[0]);
-	}
-	i = 0;
-	while (i < buflen && (c = link[i])) {
-		i++;
-		put_user (c, buffer++);
-	}
-	brelse (bh);
-	return i;
-}
-
-/*
- * XXX - blatantly stolen from minix fs
- */
-static struct dentry *
-ufs_follow_link(struct dentry * dentry, struct dentry * base)
-{
-	struct inode * inode = dentry->d_inode;
-	unsigned long int block;
-	struct buffer_head * bh = NULL;
-	char * link;
-
-	if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) {
-	        printk("ufs_follow_link: called on ino %lu dev %u/%u\n",
-	               inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
-	}
-
-	if (inode->i_blocks) {
-	        /* read the link from disk */
-	        /* XXX - error checking */
-	        block = ufs_bmap(inode, 0);
-	        bh = bread(inode->i_dev, block, inode->i_sb->s_blocksize);
-	        if (bh == NULL) {
-	                printk("ufs_follow_link: can't read block 0 for ino %lu on dev %u/%u\n",
-	                       inode->i_ino, MAJOR(inode->i_dev),
-	                       MINOR(inode->i_dev));
-			dput(base);
-	                return ERR_PTR(-EIO);
-	        }
-	        link = bh->b_data;
-	} else /* fast symlink */ {
-	        link = (char *)&(inode->u.ufs_i.i_u1.i_symlink[0]);
-	}
-	base = lookup_dentry(link, base, 1);
-	brelse (bh);
-	return base;
-}
-
-
-static struct file_operations ufs_symlink_operations = {
-	NULL,			/* lseek */
-	NULL,			/* read */
-	NULL,			/* write */
-	NULL,			/* readdir */
-	NULL,			/* select */
-	NULL,			/* ioctl */
-	NULL,			/* mmap */
-	NULL,			/* open */
-	NULL,			/* release */
-	NULL,			/* fsync */  /* XXX - is this ok? */
-	NULL,			/* fasync */
-	NULL,			/* check_media_change */
-	NULL,			/* revalidate */
-};
-
-struct inode_operations ufs_symlink_inode_operations = {
-	&ufs_symlink_operations,	/* default directory file operations */
-	NULL,			/* create */
-	NULL,			/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	&ufs_readlink,		/* readlink */
-	&ufs_follow_link,	/* follow_link */
-	NULL,			/* readpage */
-	NULL,			/* writepage */
-	NULL,			/* bmap */
-	NULL,			/* truncate */
-	NULL,			/* permission */
-};
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/util.c linux/fs/ufs/util.c
--- v2.1.111/linux/fs/ufs/util.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/ufs/util.c	Sun Jul 26 01:20:22 1998
@@ -0,0 +1,197 @@
+/*
+ *  linux/fs/ufs/util.c
+ *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles Uiversity, Faculty of Mathematics and Physics
+ */
+ 
+#include <linux/malloc.h>
+#include <linux/locks.h>
+
+#include "swab.h"
+#include "util.h"
+
+#undef UFS_UTILS_DEBUG
+
+#ifdef UFS_UTILS_DEBUG
+#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
+#else
+#define UFSD(x)
+#endif
+
+
+struct ufs_buffer_head * _ubh_bread_ (struct ufs_sb_private_info * uspi,
+	kdev_t dev, unsigned fragment, unsigned size)
+{
+	struct ufs_buffer_head * ubh;
+	unsigned i, j, count;
+	if (size & ~uspi->s_fmask)
+		return NULL;
+	count = size >> uspi->s_fshift;
+	if (count > UFS_MAXFRAG)
+		return NULL;
+	ubh = (struct ufs_buffer_head *)
+		kmalloc (sizeof (struct ufs_buffer_head), GFP_KERNEL);
+	if (!ubh)
+		return NULL;
+	ubh->fragment = fragment;
+	ubh->count = count;
+	for (i = 0; i < count; i++)
+		if (!(ubh->bh[i] = bread (dev, fragment + i, uspi->s_fsize)))
+			goto failed;
+	for (; i < UFS_MAXFRAG; i++)
+		ubh->bh[i] = NULL;
+	return ubh;
+failed:
+	for (j = 0; j < i; j++)
+		brelse (ubh->bh[j]);
+	return NULL;
+}
+
+struct ufs_buffer_head * _ubh_bread2_ (struct ufs_sb_private_info * uspi,
+	kdev_t dev, unsigned fragment, unsigned size)
+{
+	unsigned i, j, count;
+	if (size & ~uspi->s_fmask)
+		return NULL;
+	count = size >> uspi->s_fshift;
+	if (count <= 0 || count > UFS_MAXFRAG)
+		return NULL;
+	USPI_UBH->fragment = fragment;
+	USPI_UBH->count = count;
+	for (i = 0; i < count; i++)
+		if (!(USPI_UBH->bh[i] = bread (dev, fragment + i, uspi->s_fsize)))
+			goto failed;
+	for (; i < UFS_MAXFRAG; i++)
+		USPI_UBH->bh[i] = NULL;
+	return USPI_UBH;
+failed:
+	for (j = 0; j < i; j++)
+		brelse (USPI_UBH->bh[j]);
+	return NULL;
+}
+
+void ubh_brelse (struct ufs_buffer_head * ubh)
+{
+	unsigned i;
+	if (!ubh)
+		return;
+	for (i = 0; i < ubh->count; i++)
+		brelse (ubh->bh[i]);
+	kfree (ubh);
+}
+
+void ubh_brelse2 (struct ufs_buffer_head * ubh)
+{
+	unsigned i;
+	if (!ubh)
+		return;
+	for ( i = 0; i < ubh->count; i++ ) {
+		brelse (ubh->bh[i]);
+		ubh->bh[i] = NULL;
+	}
+}
+
+void ubh_mark_buffer_dirty (struct ufs_buffer_head * ubh, int flag)
+{
+	unsigned i;
+	if (!ubh)
+		return;
+	for ( i = 0; i < ubh->count; i++ )
+		mark_buffer_dirty (ubh->bh[i], flag);
+}
+
+void ubh_mark_buffer_uptodate (struct ufs_buffer_head * ubh, int flag)
+{
+	unsigned i;
+	if (!ubh)
+		return;
+	for ( i = 0; i < ubh->count; i++ )
+		mark_buffer_uptodate (ubh->bh[i], flag);
+}
+
+void ubh_ll_rw_block (int rw, unsigned nr, struct ufs_buffer_head * ubh[])
+{
+	unsigned i;
+	if (!ubh)
+		return;
+	for ( i = 0; i < nr; i++ )
+		ll_rw_block (rw, ubh[i]->count, ubh[i]->bh);
+}
+
+void ubh_wait_on_buffer (struct ufs_buffer_head * ubh)
+{
+	unsigned i;
+	if (!ubh)
+		return;
+	for ( i = 0; i < ubh->count; i++ )
+		wait_on_buffer (ubh->bh[i]);
+}
+
+unsigned ubh_max_bcount (struct ufs_buffer_head * ubh)
+{
+	unsigned i;
+	unsigned max = 0;
+	if (!ubh)
+		return 0;
+	for ( i = 0; i < ubh->count; i++ ) 
+		if ( ubh->bh[i]->b_count > max )
+			max = ubh->bh[i]->b_count;
+	if (max == 0)
+		printk("Je cosi shnileho v kralovstvi Danskem!\n");
+	return max;
+}
+
+void ubh_bforget (struct ufs_buffer_head * ubh)
+{
+	unsigned i;
+	if (!ubh) 
+		return;
+	for ( i = 0; i < ubh->count; i++ ) if ( ubh->bh[i] ) 
+		bforget (ubh->bh[i]);
+}
+ 
+int ubh_buffer_dirty (struct ufs_buffer_head * ubh)
+{
+	unsigned i;
+	unsigned result = 0;
+	if (!ubh)
+		return 0;
+	for ( i = 0; i < ubh->count; i++ )
+		result |= buffer_dirty(ubh->bh[i]);
+	return result;
+}
+
+void _ubh_ubhcpymem_(struct ufs_sb_private_info * uspi, 
+	unsigned char * mem, struct ufs_buffer_head * ubh, unsigned size)
+{
+	unsigned len, bhno;
+	if ( size > (ubh->count << uspi->s_fshift) )
+		size = ubh->count << uspi->s_fshift;
+	bhno = 0;
+	while ( size ) {
+		len = min (size, uspi->s_fsize);
+		memcpy (mem, ubh->bh[bhno]->b_data, len);
+		mem += uspi->s_fsize;
+		size -= len;
+		bhno++;
+	}
+}
+
+void _ubh_memcpyubh_(struct ufs_sb_private_info * uspi, 
+	struct ufs_buffer_head * ubh, unsigned char * mem, unsigned size)
+{
+	unsigned len, bhno;
+	if ( size > (ubh->count << uspi->s_fshift) )
+		size = ubh->count << uspi->s_fshift;
+	bhno = 0;
+	while ( size ) {
+		len = min (size, uspi->s_fsize);
+		memcpy (ubh->bh[bhno]->b_data, mem, len);
+		mem += uspi->s_fsize;
+		size -= len;
+		bhno++;
+	}
+}
+		
\ No newline at end of file
diff -u --recursive --new-file v2.1.111/linux/fs/ufs/util.h linux/fs/ufs/util.h
--- v2.1.111/linux/fs/ufs/util.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/ufs/util.h	Sun Jul 26 01:20:22 1998
@@ -0,0 +1,322 @@
+/*
+ *  linux/fs/ufs/util.h
+ *
+ * Copyright (C) 1998 
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ */
+
+#include <linux/fs.h>
+#include "swab.h"
+
+
+/*
+ * some usefull marcos
+ */
+#define in_range(b,first,len)	((b)>=(first)&&(b)<(first)+(len))
+#define howmany(x,y)		(((x)+(y)-1)/(y))
+#define min(x,y)		((x)<(y)?(x):(y))
+#define max(x,y)		((x)>(y)?(x):(y))
+
+
+/*
+ * current filesystem state; method depends on flags
+ */
+#define ufs_state(usb3) \
+	(((flags & UFS_ST_MASK) == UFS_ST_OLD) \
+	? (usb3)->fs_u.fs_sun.fs_state /* old normal way */ \
+	: (usb3)->fs_u.fs_44.fs_state /* 4.4BSD way */)
+
+/*
+ * namlen, it's format depends of flags
+ */
+#define ufs_namlen(de) _ufs_namlen_(de,flags,swab)
+static inline __u16 _ufs_namlen_(struct ufs_dir_entry * de, unsigned flags, unsigned swab) {
+	if ((flags & UFS_DE_MASK) == UFS_DE_OLD) {
+		return SWAB16(de->d_u.d_namlen);
+	} else /* UFS_DE_44BSD */ {
+		return de->d_u.d_44.d_namlen;
+	}
+}
+
+/*
+ * Here is how the uid is computed:
+ * if the file system is 4.2BSD, get it from oldids.
+ * if it has sun extension and oldids is USEEFT, get it from ui_sun.
+ * if it is 4.4 or Hurd, get it from ui_44 (which is the same as ui_hurd).
+ */
+#define ufs_uid(inode) _ufs_uid_(inode,flags,swab)
+static inline __u32 _ufs_uid_(struct ufs_inode * inode, unsigned flags, unsigned swab) {
+	switch (flags & UFS_UID_MASK) {
+		case UFS_UID_EFT:
+			return SWAB32(inode->ui_u3.ui_sun.ui_uid);
+		case UFS_UID_44BSD:
+			return SWAB32(inode->ui_u3.ui_44.ui_uid);
+		case UFS_UID_OLD:
+		default:
+			return SWAB16(inode->ui_u1.oldids.ui_suid);
+	}
+}
+
+#define ufs_gid(inode) _ufs_gid_(inode,flags,swab)
+static inline __u32 _ufs_gid_(struct ufs_inode * inode, unsigned flags, unsigned swab) {
+	switch (flags & UFS_UID_MASK) {
+		case UFS_UID_EFT:
+			return SWAB32(inode->ui_u3.ui_sun.ui_gid);
+		case UFS_UID_44BSD:
+			return SWAB32(inode->ui_u3.ui_44.ui_gid);
+		case UFS_UID_OLD:
+		default:
+			return SWAB16(inode->ui_u1.oldids.ui_sgid);
+	}
+}
+
+/*
+ * marcros used for retyping
+ */
+#define UCPI_UBH ((struct ufs_buffer_head *)ucpi)
+#define USPI_UBH ((struct ufs_buffer_head *)uspi)
+
+/*
+ * This functions manipulate with ufs_buffers
+ */
+#define ubh_bread(dev,fragment,size) _ubh_bread_(uspi,dev,fragment,size)  
+extern struct ufs_buffer_head * _ubh_bread_(struct ufs_sb_private_info *, kdev_t, unsigned, unsigned);
+#define ubh_bread2(dev,fragment,size) _ubh_bread2_(uspi,dev,fragment,size)  
+extern struct ufs_buffer_head * _ubh_bread2_(struct ufs_sb_private_info *, kdev_t, unsigned, unsigned);
+extern void ubh_brelse (struct ufs_buffer_head *);
+extern void ubh_brelse2 (struct ufs_buffer_head *);
+extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *, int);
+extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int);
+extern void ubh_ll_rw_block (int, unsigned, struct ufs_buffer_head **);
+extern void ubh_wait_on_buffer (struct ufs_buffer_head *);
+extern unsigned ubh_max_bcount (struct ufs_buffer_head *);
+extern void ubh_bforget (struct ufs_buffer_head *);
+extern int  ubh_buffer_dirty (struct ufs_buffer_head *);
+#define ubh_ubhcpymem(mem,ubh,size) _ubh_ubhcpymem_(uspi,mem,ubh,size)
+extern void _ubh_ubhcpymem_(struct ufs_sb_private_info *, unsigned char *, struct ufs_buffer_head *, unsigned);
+#define ubh_memcpyubh(ubh,mem,size) _ubh_memcpyubh_(uspi,ubh,mem,size)
+extern void _ubh_memcpyubh_(struct ufs_sb_private_info *, struct ufs_buffer_head *, unsigned char *, unsigned);
+
+/*
+ * macros to get important structures from ufs_buffer_head
+ */
+#define ubh_get_usb_first(ubh) \
+	((struct ufs_super_block_first *)((ubh)->bh[0]->b_data))
+
+#define ubh_get_usb_second(ubh) \
+	((struct ufs_super_block_second *)(ubh)-> \
+	bh[SECTOR_SIZE >> uspi->s_fshift]->b_data + (SECTOR_SIZE & ~uspi->s_fmask))
+
+#define ubh_get_usb_third(ubh) \
+	((struct ufs_super_block_third *)((ubh)-> \
+	bh[SECTOR_SIZE*2 >> uspi->s_fshift]->b_data + (SECTOR_SIZE*2 & ~uspi->s_fmask)))
+
+#define ubh_get_ucg(ubh) \
+	((struct ufs_cylinder_group *)((ubh)->bh[0]->b_data))
+
+/*
+ * Extract byte from ufs_buffer_head
+ * Extract the bits for a block from a map inside ufs_buffer_head
+ */
+#define ubh_get_addr8(ubh,begin) \
+	((u8*)(ubh)->bh[(begin) >> uspi->s_fshift]->b_data + ((begin) & ~uspi->s_fmask))
+
+#define ubh_get_addr16(ubh,begin) \
+	(((u16*)((ubh)->bh[(begin) >> (uspi->s_fshift-1)]->b_data)) + ((begin) & (uspi->fsize>>1) - 1)))
+
+#define ubh_get_addr32(ubh,begin) \
+	(((u32*)((ubh)->bh[(begin) >> (BLOCK_SIZE_BITS-2)]->b_data)) + \
+	((begin) & ((BLOCK_SIZE>>2) - 1)))
+
+#define ubh_get_addr ubh_get_addr8
+
+#define ubh_blkmap(ubh,begin,bit) \
+	((*ubh_get_addr(ubh, (begin) + ((bit) >> 3)) >> ((bit) & 7)) & (0xff >> (UFS_MAXFRAG - uspi->s_fpb)))
+
+/*
+ * Macros for access to superblock array structures
+ */
+#define ubh_postbl(ubh,cylno,i) \
+	((uspi->s_postblformat != UFS_DYNAMICPOSTBLFMT) \
+	? (*(__s16*)(ubh_get_addr(ubh, \
+	(unsigned)(&((struct ufs_super_block *)0)->fs_opostbl) \
+	+ (((cylno) * 16 + (i)) << 1) ) )) \
+	: (*(__s16*)(ubh_get_addr(ubh, \
+	uspi->s_postbloff + (((cylno) * uspi->s_nrpos + (i)) << 1) ))))
+
+#define ubh_rotbl(ubh,i) \
+	((uspi->s_postblformat != UFS_DYNAMICPOSTBLFMT) \
+	? (*(__u8*)(ubh_get_addr(ubh, \
+	(unsigned)(&((struct ufs_super_block *)0)->fs_space) + (i)))) \
+	: (*(__u8*)(ubh_get_addr(ubh, uspi->s_rotbloff + (i)))))
+
+/*
+ * Determine the number of available frags given a
+ * percentage to hold in reserve.
+ */
+#define ufs_freespace(usb, percentreserved) \
+	(ufs_blkstofrags(SWAB32((usb)->fs_cstotal.cs_nbfree)) + \
+	SWAB32((usb)->fs_cstotal.cs_nffree) - (uspi->s_dsize * (percentreserved) / 100))
+
+/*
+ * Macros for access to cylinder group array structures
+ */
+#define ubh_cg_blktot(ucpi,cylno) \
+	(*((__u32*)ubh_get_addr(UCPI_UBH, (ucpi)->c_btotoff + ((cylno) << 2))))
+
+#define ubh_cg_blks(ucpi,cylno,rpos) \
+	(*((__u16*)ubh_get_addr(UCPI_UBH, \
+	(ucpi)->c_boff + (((cylno) * uspi->s_nrpos + (rpos)) << 1 ))))
+
+/*
+ * Bitmap operation
+ * This functions work like classical bitmap operations. The diference 
+ * is that we havn't the whole bitmap in one continuous part of memory,
+ * but in a few buffers.
+ * The parameter of each function is super_block, ufs_buffer_head and
+ * position of the begining of the bitmap.
+ */
+#define ubh_setbit(ubh,begin,bit) \
+	(*ubh_get_addr(ubh, (begin) + ((bit) >> 3)) |= (1 << ((bit) & 7)))
+
+#define ubh_clrbit(ubh,begin,bit) \
+	(*ubh_get_addr (ubh, (begin) + ((bit) >> 3)) &= ~(1 << ((bit) & 7)))
+
+#define ubh_isset(ubh,begin,bit) \
+	(*ubh_get_addr (ubh, (begin) + ((bit) >> 3)) & (1 << ((bit) & 7)))
+
+#define ubh_isclr(ubh,begin,bit) (!ubh_isset(ubh,begin,bit))
+
+#define ubh_find_first_zero_bit(ubh,begin,size) _ubh_find_next_zero_bit_(uspi,ubh,begin,size,0)
+#define ubh_find_next_zero_bit(ubh,begin,size,offset) _ubh_find_next_zero_bit_(uspi,ubh,begin,size,offset)
+static inline unsigned _ubh_find_next_zero_bit_(
+	struct ufs_sb_private_info * uspi, struct ufs_buffer_head * ubh,
+	unsigned begin, unsigned size, unsigned offset)
+{
+	unsigned base, rest;
+
+	begin <<= 3;
+	size += begin;
+	offset += begin;
+	base = offset >> (uspi->s_fshift + 3);
+	offset &= ((uspi->s_fsize << 3) - 1);
+	for (;;) {
+		rest = min (size, uspi->s_fsize << 3);
+		size -= rest;
+		offset = ext2_find_next_zero_bit (ubh->bh[base]->b_data, rest, offset);
+		if (offset < rest || !size)
+			break;
+		base++;
+		offset = 0;
+	}
+	return (base << (uspi->s_fshift + 3)) + offset - begin;
+} 	
+
+#define ubh_isblockclear(ubh,begin,block) (!_ubh_isblockset_(uspi,ubh,begin,block))
+#define ubh_isblockset(ubh,begin,block) _ubh_isblockset_(uspi,ubh,begin,block)
+static inline int _ubh_isblockset_(struct ufs_sb_private_info * uspi,
+	struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
+{
+	switch (uspi->s_fpb) {
+	case 8:
+	    	return (*ubh_get_addr (ubh, begin + block) == 0xff);
+	case 4:
+		return (*ubh_get_addr (ubh, begin + (block >> 1)) == (0x0f << ((block & 0x01) << 2)));
+	case 2:
+		return (*ubh_get_addr (ubh, begin + (block >> 2)) == (0x03 << ((block & 0x03) << 1)));
+	case 1:
+		return (*ubh_get_addr (ubh, begin + (block >> 3)) == (0x01 << (block & 0x07)));
+	}
+	return 0;	
+}
+
+#define ubh_clrblock(ubh,begin,block) _ubh_clrblock_(uspi,ubh,begin,block)
+static inline void _ubh_clrblock_(struct ufs_sb_private_info * uspi,
+	struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
+{
+	switch (uspi->s_fpb) {
+	case 8:
+	    	*ubh_get_addr (ubh, begin + block) = 0x00;
+	    	return; 
+	case 4:
+		*ubh_get_addr (ubh, begin + (block >> 1)) &= ~(0x0f << ((block & 0x01) << 2));
+		return;
+	case 2:
+		*ubh_get_addr (ubh, begin + (block >> 2)) &= ~(0x03 << ((block & 0x03) << 1));
+		return;
+	case 1:
+		*ubh_get_addr (ubh, begin + (block >> 3)) &= ~(0x01 << ((block & 0x07)));
+		return;
+	}
+}
+
+#define ubh_setblock(ubh,begin,block) _ubh_setblock_(uspi,ubh,begin,block)
+static inline void _ubh_setblock_(struct ufs_sb_private_info * uspi,
+	struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
+{
+	switch (uspi->s_fpb) {
+	case 8:
+	    	*ubh_get_addr(ubh, begin + block) = 0xff;
+	    	return;
+	case 4:
+		*ubh_get_addr(ubh, begin + (block >> 1)) |= (0x0f << ((block & 0x01) << 2));
+		return;
+	case 2:
+		*ubh_get_addr(ubh, begin + (block >> 2)) |= (0x03 << ((block & 0x03) << 1));
+		return;
+	case 1:
+		*ubh_get_addr(ubh, begin + (block >> 3)) |= (0x01 << ((block & 0x07)));
+		return;
+	}
+}
+
+static inline void ufs_fragacct (struct super_block * sb, unsigned blockmap,
+	unsigned * fraglist, int cnt)
+{
+	struct ufs_sb_private_info * uspi;
+	unsigned fragsize, pos;
+	unsigned swab;
+	
+	swab = sb->u.ufs_sb.s_swab;
+	uspi = sb->u.ufs_sb.s_uspi;
+	
+	fragsize = 0;
+	for (pos = 0; pos < uspi->s_fpb; pos++) {
+		if (blockmap & (1 << pos)) {
+			fragsize++;
+		}
+		else if (fragsize > 0) {
+			ADD_SWAB32(fraglist[fragsize], cnt);
+			fragsize = 0;
+		}
+	}
+	if (fragsize > 0 && fragsize < uspi->s_fpb)
+		ADD_SWAB32(fraglist[fragsize], cnt);
+}
+
+#define ubh_scanc(ubh,begin,size,table,mask) _ubh_scanc_(uspi,ubh,begin,size,table,mask)
+static inline unsigned _ubh_scanc_(struct ufs_sb_private_info * uspi, struct ufs_buffer_head * ubh, 
+	unsigned begin, unsigned size, unsigned char * table, unsigned char mask)
+{
+	unsigned rest, offset;
+	unsigned char * cp;
+	
+
+	offset = begin & ~uspi->s_fmask;
+	begin >>= uspi->s_fshift;
+	for (;;) {
+		if ((offset + size) < uspi->s_fsize)
+			rest = size;
+		else
+			rest = uspi->s_fsize - offset;
+		size -= rest;
+		cp = ubh->bh[begin]->b_data + offset;
+		while ((table[*cp++] & mask) == 0 && --rest);
+		if (rest || !size)
+			break;
+		begin++;
+		offset = 0;
+	}
+	return (size + rest);
+}
diff -u --recursive --new-file v2.1.111/linux/include/asm-alpha/siginfo.h linux/include/asm-alpha/siginfo.h
--- v2.1.111/linux/include/asm-alpha/siginfo.h	Tue Dec  2 16:26:07 1997
+++ linux/include/asm-alpha/siginfo.h	Mon Jul 27 16:21:45 1998
@@ -43,6 +43,7 @@
 		/* SIGCHLD */
 		struct {
 			pid_t _pid;		/* which child */
+			uid_t _uid;		/* sender's uid */
 			int _status;		/* exit code */
 			clock_t _utime;
 			clock_t _stime;
diff -u --recursive --new-file v2.1.111/linux/include/asm-alpha/smp_lock.h linux/include/asm-alpha/smp_lock.h
--- v2.1.111/linux/include/asm-alpha/smp_lock.h	Wed Apr  1 20:11:53 1998
+++ linux/include/asm-alpha/smp_lock.h	Wed Dec 31 16:00:00 1969
@@ -1,120 +0,0 @@
-#ifndef __ALPHA_SMPLOCK_H
-#define __ALPHA_SMPLOCK_H
-
-#ifndef __SMP__
-
-#define lock_kernel()				do { } while(0)
-#define unlock_kernel()				do { } while(0)
-#define release_kernel_lock(task, cpu, depth)	((depth) = 1)
-#define reacquire_kernel_lock(task, cpu, depth)	do { } while (0)
-
-#else
-
-#include <asm/system.h>
-#include <asm/current.h>
-#include <asm/bitops.h>
-#include <asm/hardirq.h>
-
-#define kernel_lock_held() \
-  (klock_info.kernel_flag && (klock_info.akp == smp_processor_id()))
-
-/* Release global kernel lock and global interrupt lock */
-#define release_kernel_lock(task, cpu, depth)		\
-do {							\
-	if ((depth = (task)->lock_depth) != 0) {	\
-		__cli();				\
-		(task)->lock_depth = 0;			\
-		klock_info.akp = NO_PROC_ID;		\
-		klock_info.kernel_flag = 0;		\
-		mb();					\
-	}						\
-	release_irqlock(cpu);				\
-	__sti();					\
-} while (0)
-
-#if 1
-#define DEBUG_KERNEL_LOCK
-#else
-#undef DEBUG_KERNEL_LOCK
-#endif
-
-#ifdef DEBUG_KERNEL_LOCK
-extern void ___lock_kernel(klock_info_t *klip, int cpu, long ipl);
-#else /* DEBUG_KERNEL_LOCK */
-static inline void ___lock_kernel(klock_info_t *klip, int cpu, long ipl)
-{
-	long regx;
-
-	__asm__ __volatile__(
-	"1:	ldl_l	%1,%0;"
-	"	blbs	%1,6f;"
-	"	or	%1,1,%1;"
-	"	stl_c	%1,%0;"
-	"	beq	%1,6f;"
-	"4:	mb\n"
-	".section .text2,\"ax\"\n"
-	"6:	mov %4,$16;"
-	"	call_pal %3;"
-	"7:	ldl %1,%0;"
-	"	blbs %1,7b;"
-	"	bis $31,7,$16;"
-	"	call_pal %3;"
-	"	br 1b\n"
-	".previous"
-	: "=m,=m" (__dummy_lock(klip)), "=&r,=&r" (regx)
-	: "0,0" (__dummy_lock(klip)), "i,i" (PAL_swpipl), "i,r" (ipl)
-	: "$0", "$1", "$16", "$22", "$23", "$24", "$25", "memory"
-	);
-}
-#endif /* DEBUG_KERNEL_LOCK */
-
-#define reacquire_kernel_lock(task, cpu, depth)	\
-do {						\
-  if (depth) {					\
-    long ipl;					\
-    klock_info_t *klip = &klock_info;		\
-    __save_and_cli(ipl);			\
-    ___lock_kernel(klip, cpu, ipl);		\
-    klip->akp = cpu;				\
-    (task)->lock_depth = depth;			\
-    __restore_flags(ipl);			\
-  }						\
-} while (0)
-
-/* The following acquire and release the master kernel global lock,
- * the idea is that the usage of this mechanmism becomes less and less
- * as time goes on, to the point where they are no longer needed at all
- * and can thus disappear.
- */
-
-#define lock_kernel()				\
-if (current->lock_depth > 0) {			\
-     ++current->lock_depth;			\
-} else {					\
-  long ipl;					\
-  int cpu = smp_processor_id();			\
-  klock_info_t *klip = &klock_info;		\
-  __save_and_cli(ipl);				\
-  ___lock_kernel(klip, cpu, ipl);		\
-  klip->akp = cpu;				\
-  current->lock_depth = 1;			\
-  __restore_flags(ipl);				\
-}
-
-/* Release kernel global lock. */
-#define unlock_kernel()				\
-if (current->lock_depth > 1) {			\
-  --current->lock_depth;			\
-} else {					\
-  long ipl;					\
-  __save_and_cli(ipl);				\
-  klock_info.akp = NO_PROC_ID;			\
-  klock_info.kernel_flag = KLOCK_CLEAR;		\
-  mb();						\
-  current->lock_depth = 0;			\
-  __restore_flags(ipl);				\
-}  
-
-#endif /* __SMP__ */
-
-#endif /* __ALPHA_SMPLOCK_H */
diff -u --recursive --new-file v2.1.111/linux/include/asm-arm/siginfo.h linux/include/asm-arm/siginfo.h
--- v2.1.111/linux/include/asm-arm/siginfo.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/siginfo.h	Mon Jul 27 16:21:45 1998
@@ -43,6 +43,7 @@
 		/* SIGCHLD */
 		struct {
 			pid_t _pid;		/* which child */
+			uid_t _uid;		/* sender's uid */
 			int _status;		/* exit code */
 			clock_t _utime;
 			clock_t _stime;
diff -u --recursive --new-file v2.1.111/linux/include/asm-arm/smp_lock.h linux/include/asm-arm/smp_lock.h
--- v2.1.111/linux/include/asm-arm/smp_lock.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/smp_lock.h	Wed Dec 31 16:00:00 1969
@@ -1,17 +0,0 @@
-#ifndef __I386_SMPLOCK_H
-#define __I386_SMPLOCK_H
-
-#define __STR(x) #x
-
-#ifndef __SMP__
-
-#define lock_kernel()				do { } while(0)
-#define unlock_kernel()				do { } while(0)
-#define release_kernel_lock(task, cpu, depth)	((depth) = 1)
-#define reacquire_kernel_lock(task, cpu, depth)	do { } while(0)
-
-#else
-#error SMP not supported
-#endif /* __SMP__ */
-
-#endif /* __I386_SMPLOCK_H */
diff -u --recursive --new-file v2.1.111/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h
--- v2.1.111/linux/include/asm-i386/bugs.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-i386/bugs.h	Tue Jul 28 13:51:19 1998
@@ -19,10 +19,6 @@
 #include <linux/config.h>
 #include <asm/processor.h>
 
-#ifdef CONFIG_MTRR
-#  include <asm/mtrr.h>
-#endif
-
 #define CONFIG_BUGi386
 
 __initfunc(static void no_halt(char *s, int *ints))
@@ -333,7 +329,4 @@
 	check_amd_k6();
 	check_pentium_f00f();
 	system_utsname.machine[1] = '0' + boot_cpu_data.x86;
-#if defined(CONFIG_MTRR)
-	mtrr_init ();
-#endif
 }
diff -u --recursive --new-file v2.1.111/linux/include/asm-i386/siginfo.h linux/include/asm-i386/siginfo.h
--- v2.1.111/linux/include/asm-i386/siginfo.h	Fri Feb  6 15:32:54 1998
+++ linux/include/asm-i386/siginfo.h	Mon Jul 27 16:21:45 1998
@@ -43,6 +43,7 @@
 		/* SIGCHLD */
 		struct {
 			pid_t _pid;		/* which child */
+			uid_t _uid;		/* sender's uid */
 			int _status;		/* exit code */
 			clock_t _utime;
 			clock_t _stime;
diff -u --recursive --new-file v2.1.111/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- v2.1.111/linux/include/asm-i386/smp.h	Sun Jul 26 11:57:19 1998
+++ linux/include/asm-i386/smp.h	Mon Jul 27 17:43:08 1998
@@ -7,6 +7,7 @@
 #include <asm/i82489.h>
 #include <asm/bitops.h>
 #include <asm/fixmap.h>
+
 #include <linux/tasks.h>
 #include <linux/ptrace.h>
 
@@ -161,9 +162,8 @@
 extern volatile int cpu_number_map[NR_CPUS];
 extern volatile unsigned long smp_invalidate_needed;
 extern void smp_flush_tlb(void);
-extern volatile unsigned long kernel_flag, kernel_counter;
+
 extern volatile unsigned long cpu_callin_map[NR_CPUS];
-extern volatile unsigned char active_kernel_processor;
 extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
 extern void smp_send_reschedule(int cpu);
 extern unsigned long ipi_count;
diff -u --recursive --new-file v2.1.111/linux/include/asm-i386/smp_lock.h linux/include/asm-i386/smp_lock.h
--- v2.1.111/linux/include/asm-i386/smp_lock.h	Fri Feb  6 15:32:54 1998
+++ linux/include/asm-i386/smp_lock.h	Wed Dec 31 16:00:00 1969
@@ -1,91 +0,0 @@
-#ifndef __I386_SMPLOCK_H
-#define __I386_SMPLOCK_H
-
-#define __STR(x) #x
-
-#ifndef __SMP__
-
-#define lock_kernel()				do { } while(0)
-#define unlock_kernel()				do { } while(0)
-#define release_kernel_lock(task, cpu, depth)	((depth) = 1)
-#define reacquire_kernel_lock(task, cpu, depth)	do { } while(0)
-
-#else
-
-#include <asm/hardirq.h>
-
-/* Release global kernel lock and global interrupt lock */
-#define release_kernel_lock(task, cpu, depth) \
-do { \
-	if ((depth = (task)->lock_depth) != 0) { \
-		__cli(); \
-		(task)->lock_depth = 0; \
-		active_kernel_processor = NO_PROC_ID; \
-		clear_bit(0,&kernel_flag); \
-	} \
-	release_irqlock(cpu); \
-	__sti(); \
-} while (0)
-
-/* Re-acquire the kernel lock */
-#define reacquire_kernel_lock(task, cpu, depth) \
-do { if (depth) __asm__ __volatile__( \
-	"cli\n\t" \
-	"call __lock_kernel\n\t" \
-	"movl %2,%0\n\t" \
-	"sti" \
-	: "=m" (task->lock_depth) \
-	: "d" (cpu), "c" (depth)); \
-} while (0)
-	
-
-extern const char lk_lockmsg[]; 
-
-/* Locking the kernel */
-extern __inline__ void lock_kernel(void)
-{
-	int cpu = smp_processor_id();
-
-	if (local_irq_count[cpu]) {
-		__label__ l1;
-l1:		printk(lk_lockmsg, &&l1);
-	}
-	if (cpu == global_irq_holder) {
-		__label__ l2;
-l2:		printk("Ugh at %p\n", &&l2);
-		sti();
-	}
-
-	__asm__ __volatile__("
-	pushfl
-	cli
-	cmpl	$0, %0
-	jne	0f
-	call	__lock_kernel
-0:	incl	%0
-	popfl
-"	:
-	: "m" (current->lock_depth), "d" (cpu)
-	: "memory");
-}
-
-extern __inline__ void unlock_kernel(void)
-{
-	__asm__ __volatile__("
-	pushfl
-	cli
-	decl	%0
-	jnz	1f
-	movb	%1, " __STR(active_kernel_processor) "
-	lock
-	btrl	$0, " __STR(kernel_flag) "
-1:
-	popfl
-"	: /* no outputs */
-	: "m" (current->lock_depth), "i" (NO_PROC_ID)
-	: "ax", "memory");
-}
-
-#endif /* __SMP__ */
-
-#endif /* __I386_SMPLOCK_H */
diff -u --recursive --new-file v2.1.111/linux/include/asm-m68k/siginfo.h linux/include/asm-m68k/siginfo.h
--- v2.1.111/linux/include/asm-m68k/siginfo.h	Tue Feb 17 13:12:49 1998
+++ linux/include/asm-m68k/siginfo.h	Mon Jul 27 16:21:45 1998
@@ -43,6 +43,7 @@
 		/* SIGCHLD */
 		struct {
 			pid_t _pid;		/* which child */
+			uid_t _uid;		/* sender's uid */
 			int _status;		/* exit code */
 			clock_t _utime;
 			clock_t _stime;
diff -u --recursive --new-file v2.1.111/linux/include/asm-m68k/smp_lock.h linux/include/asm-m68k/smp_lock.h
--- v2.1.111/linux/include/asm-m68k/smp_lock.h	Tue May 13 22:41:17 1997
+++ linux/include/asm-m68k/smp_lock.h	Wed Dec 31 16:00:00 1969
@@ -1,14 +0,0 @@
-#ifndef __M68K_SMPLOCK_H
-#define __M68K_SMPLOCK_H
-
-/*
- * We don't do SMP so this is again one of these silly dummy files
- * to keep the kernel source looking nice ;-(.
- */
-
-#define lock_kernel()		do { } while(0)
-#define unlock_kernel()		do { } while(0)
-#define release_kernel_lock(task, cpu, depth)	((depth) = 1)
-#define reacquire_kernel_lock(task, cpu, depth)	do { } while(0)
-
-#endif
diff -u --recursive --new-file v2.1.111/linux/include/asm-mips/siginfo.h linux/include/asm-mips/siginfo.h
--- v2.1.111/linux/include/asm-mips/siginfo.h	Tue Dec 16 12:46:14 1997
+++ linux/include/asm-mips/siginfo.h	Mon Jul 27 16:21:45 1998
@@ -43,6 +43,7 @@
 		/* SIGCHLD */
 		struct {
 			pid_t _pid;		/* which child */
+			uid_t _uid;		/* sender's uid */
 			int _status;		/* exit code */
 			clock_t _utime;
 			clock_t _stime;
diff -u --recursive --new-file v2.1.111/linux/include/asm-mips/smp_lock.h linux/include/asm-mips/smp_lock.h
--- v2.1.111/linux/include/asm-mips/smp_lock.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/smp_lock.h	Wed Dec 31 16:00:00 1969
@@ -1,26 +0,0 @@
-/*
- * 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) 1996  Ralf Baechle
- *
- * Linux/MIPS SMP support.  Just a dummy to make building possible.
- */
-#ifndef __ASM_MIPS_SMPLOCK_H
-#define __ASM_MIPS_SMPLOCK_H
-
-#ifndef __SMP__
-
-#define lock_kernel()		do { } while(0)
-#define unlock_kernel()		do { } while(0)
-#define release_kernel_lock(task, cpu, depth)  ((depth) = 1)
-#define reacquire_kernel_lock(task, cpu, depth) do { } while(0)
-
-#else
-
-#error "We do not support SMP on MIPS yet"
-
-#endif /* __SMP__ */
-
-#endif /* __ASM_MIPS_SMPLOCK_H */
diff -u --recursive --new-file v2.1.111/linux/include/asm-ppc/siginfo.h linux/include/asm-ppc/siginfo.h
--- v2.1.111/linux/include/asm-ppc/siginfo.h	Mon Jan 12 15:18:13 1998
+++ linux/include/asm-ppc/siginfo.h	Mon Jul 27 16:21:45 1998
@@ -43,6 +43,7 @@
 		/* SIGCHLD */
 		struct {
 			pid_t _pid;		/* which child */
+			uid_t _uid;		/* sender's uid */
 			int _status;		/* exit code */
 			clock_t _utime;
 			clock_t _stime;
diff -u --recursive --new-file v2.1.111/linux/include/asm-ppc/smp_lock.h linux/include/asm-ppc/smp_lock.h
--- v2.1.111/linux/include/asm-ppc/smp_lock.h	Mon Jan 12 15:18:13 1998
+++ linux/include/asm-ppc/smp_lock.h	Wed Dec 31 16:00:00 1969
@@ -1,49 +0,0 @@
-#ifndef __PPC_SMPLOCK_H
-#define __PPC_SMPLOCK_H
-
-#ifndef __SMP__
-
-#define lock_kernel()		do { } while (0)
-#define unlock_kernel()		do { } while (0)
-#define release_kernel_lock(task, cpu, depth)	((depth) = 1)
-#define reacquire_kernel_lock(task, cpu, depth)	do { } while(0)
-
-#else /* __SMP__ */
-
-/* Release global kernel lock and global interrupt lock */
-#define release_kernel_lock(task, cpu, depth)		\
-do {							\
-	if((depth = (task)->lock_depth) != 0) {		\
-		__cli();				\
-		(task)->lock_depth = 0;			\
-		klock_info.akp = NO_PROC_ID;		\
-		klock_info.kernel_flag = 0;		\
-	} 						\
-	release_irqlock(cpu);				\
-	__sti();					\
-} while(0)
-
-extern void reacquire_kernel_lock(struct task_struct *, int,int);
-
-/* The following acquire and release the master kernel global lock,
- * the idea is that the usage of this mechanmism becomes less and less
- * as time goes on, to the point where they are no longer needed at all
- * and can thus disappear.
- */
-extern void __lock_kernel(struct task_struct *);
-extern void __unlock_kernel(struct task_struct *);
-
-extern __inline__ void lock_kernel(void)
-{
-	__lock_kernel(current);
-}
-
-/* Release kernel global lock. */
-extern __inline__ void unlock_kernel(void)
-{
-	__unlock_kernel(current);
-}
-
-
-#endif /* __SMP__ */
-#endif /* __PPC_SMPLOCK_H */
diff -u --recursive --new-file v2.1.111/linux/include/asm-sparc/siginfo.h linux/include/asm-sparc/siginfo.h
--- v2.1.111/linux/include/asm-sparc/siginfo.h	Mon Jan 12 15:15:54 1998
+++ linux/include/asm-sparc/siginfo.h	Mon Jul 27 16:21:45 1998
@@ -45,6 +45,7 @@
 		/* SIGCHLD */
 		struct {
 			pid_t _pid;		/* which child */
+			uid_t _uid;		/* sender's uid */
 			int _status;		/* exit code */
 			clock_t _utime;
 			clock_t _stime;
diff -u --recursive --new-file v2.1.111/linux/include/asm-sparc/smp_lock.h linux/include/asm-sparc/smp_lock.h
--- v2.1.111/linux/include/asm-sparc/smp_lock.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-sparc/smp_lock.h	Wed Dec 31 16:00:00 1969
@@ -1,89 +0,0 @@
-/* smp_lock.h: 32-bit Sparc SMP master lock primitives.
- *
- * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef __SPARC_SMPLOCK_H
-#define __SPARC_SMPLOCK_H
-
-#include <asm/smp.h>
-#include <asm/ptrace.h>
-
-#ifndef __SMP__
-
-#define lock_kernel()				do { } while(0)
-#define unlock_kernel()				do { } while(0)
-#define release_kernel_lock(task, cpu, depth)	((depth) = 1)
-#define reacquire_kernel_lock(task, cpu, depth)	do { } while(0)
-
-#else
-
-#include <asm/hardirq.h>
-
-/* Release global kernel lock and global interrupt lock */
-#define release_kernel_lock(task, cpu, depth)		\
-do {							\
-	if((depth = (task)->lock_depth) != 0) {		\
-		__cli();				\
-		(task)->lock_depth = 0;			\
-		klock_info.akp = NO_PROC_ID;		\
-		klock_info.kernel_flag = 0;		\
-	}						\
-	release_irqlock(cpu);				\
-	__sti();					\
-} while(0)
-
-/* Do not fuck with this without consulting arch/sparc/lib/locks.S first! */
-#define reacquire_kernel_lock(task, cpu, depth)					\
-do {										\
-	if(depth) {								\
-		register struct klock_info *klip asm("g1");			\
-		register int proc asm("g5");					\
-		klip = &klock_info;						\
-		proc = cpu;							\
-		__asm__ __volatile__("mov	%%o7, %%g4\n\t"			\
-				     "call	___lock_reacquire_kernel\n\t"	\
-				     " mov	%2, %%g2"			\
-				     : /* No outputs. */			\
-				     : "r" (klip), "r" (proc), "r" (depth)	\
-				     : "g2", "g3", "g4", "g7", "memory", "cc");	\
-	}									\
-} while(0)
-
-/* The following acquire and release the master kernel global lock,
- * the idea is that the usage of this mechanmism becomes less and less
- * as time goes on, to the point where they are no longer needed at all
- * and can thus disappear.
- */
-
-/* Do not fuck with this without consulting arch/sparc/lib/locks.S first! */
-extern __inline__ void lock_kernel(void)
-{
-	register struct klock_info *klip asm("g1");
-	register int proc asm("g5");
-	klip = &klock_info;
-	proc = smp_processor_id();
-	__asm__ __volatile__("
-	mov	%%o7, %%g4
-	call	___lock_kernel
-	 ld	[%%g6 + %0], %%g2
-"	: : "i" (AOFF_task_lock_depth), "r" (klip), "r" (proc)
-	: "g2", "g3", "g4", "g7", "memory", "cc");
-}
-
-/* Release kernel global lock. */
-extern __inline__ void unlock_kernel(void)
-{
-	register struct klock_info *klip asm("g1");
-	klip = &klock_info;
-	__asm__ __volatile__("
-	mov	%%o7, %%g4
-	call	___unlock_kernel
-	 ld	[%%g6 + %0], %%g2
-"	: : "i" (AOFF_task_lock_depth), "r" (klip)
-	: "g2", "g3", "g4", "memory", "cc");
-}
-
-#endif /* !(__SPARC_SMPLOCK_H) */
-
-#endif /* (__SMP__) */
diff -u --recursive --new-file v2.1.111/linux/include/asm-sparc64/siginfo.h linux/include/asm-sparc64/siginfo.h
--- v2.1.111/linux/include/asm-sparc64/siginfo.h	Mon Jan 12 15:15:58 1998
+++ linux/include/asm-sparc64/siginfo.h	Mon Jul 27 16:21:45 1998
@@ -51,6 +51,7 @@
 		/* SIGCHLD */
 		struct {
 			pid_t _pid;		/* which child */
+			uid_t _uid;		/* sender's uid */
 			int _status;		/* exit code */
 			clock_t _utime;
 			clock_t _stime;
diff -u --recursive --new-file v2.1.111/linux/include/asm-sparc64/smp_lock.h linux/include/asm-sparc64/smp_lock.h
--- v2.1.111/linux/include/asm-sparc64/smp_lock.h	Sat Aug 16 09:51:10 1997
+++ linux/include/asm-sparc64/smp_lock.h	Wed Dec 31 16:00:00 1969
@@ -1,87 +0,0 @@
-/* smp_lock.h: Locking and unlocking the kernel on the 64-bit Sparc.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef __SPARC64_SMPLOCK_H
-#define __SPARC64_SMPLOCK_H
-
-#include <asm/smp.h>
-#include <asm/bitops.h>
-#include <asm/pgtable.h>
-
-#ifndef __SMP__
-
-#define lock_kernel()				do { } while(0)
-#define unlock_kernel()				do { } while(0)
-#define release_kernel_lock(task, cpu, depth)	((depth) = 1)
-#define reacquire_kernel_lock(task, cpu, depth)	do { } while(0)
-
-#else
-
-#include <asm/hardirq.h>
-
-/* Release global kernel lock and global interrupt lock */
-#define release_kernel_lock(task, cpu, depth)		\
-do {							\
-	if((depth = (task)->lock_depth) != 0) {		\
-		__cli();				\
-		(task)->lock_depth = 0;			\
-		klock_info.akp = NO_PROC_ID;		\
-		membar("#LoadStore | #StoreStore");	\
-		klock_info.kernel_flag = 0;		\
-	}						\
-	release_irqlock(cpu);				\
-	__sti();					\
-} while(0)
-
-/* Do not fuck with this without consulting arch/sparc64/lib/locks.S first! */
-#define reacquire_kernel_lock(task, cpu, depth)					\
-do {										\
-	if(depth) {								\
-		register struct klock_info *klip asm("g1");			\
-		klip = &klock_info;						\
-		__asm__ __volatile__("mov	%%o7, %%g5\n\t"			\
-				     "call	___lock_reacquire_kernel\n\t"	\
-				     " mov	%1, %%g2"			\
-				     : /* No outputs. */			\
-				     : "r" (klip), "r" (depth)			\
-				     : "g2", "g3", "g5", "memory", "cc");	\
-	}									\
-} while(0)
-
-/* The following acquire and release the master kernel global lock,
- * the idea is that the usage of this mechanmism becomes less and less
- * as time goes on, to the point where they are no longer needed at all
- * and can thus disappear.
- */
-
-/* Do not fuck with this without consulting arch/sparc64/lib/locks.S first! */
-extern __inline__ void lock_kernel(void)
-{
-	register struct klock_info *klip asm("g1");
-	klip = &klock_info;
-	__asm__ __volatile__("
-	mov	%%o7, %%g5
-	call	___lock_kernel
-	 lduw	[%%g6 + %0], %%g2
-"	: : "i" (AOFF_task_lock_depth), "r" (klip)
-	: "g2", "g3", "g5", "memory", "cc");
-}
-
-/* Release kernel global lock. */
-extern __inline__ void unlock_kernel(void)
-{
-	register struct klock_info *klip asm("g1");
-	klip = &klock_info;
-	__asm__ __volatile__("
-	mov	%%o7, %%g5
-	call	___unlock_kernel
-	 lduw	[%%g6 + %0], %%g2
-"	: : "i" (AOFF_task_lock_depth), "r" (klip)
-	: "g2", "g3", "g5", "memory", "cc");
-}
-
-#endif /* (__SMP__) */
-
-#endif /* !(__SPARC64_SMPLOCK_H) */
diff -u --recursive --new-file v2.1.111/linux/include/linux/console_struct.h linux/include/linux/console_struct.h
--- v2.1.111/linux/include/linux/console_struct.h	Sun Jul 26 11:57:19 1998
+++ linux/include/linux/console_struct.h	Sun Jul 26 14:40:19 1998
@@ -15,6 +15,8 @@
  */
 #define CUR_DEFAULT CUR_UNDERLINE
 
+#include <linux/config.h>
+
 #define NPAR 16
 
 struct vc_data {
@@ -33,7 +35,7 @@
 	unsigned char	vc_ulcolor;		/* Color for underline mode */
 	unsigned char	vc_halfcolor;		/* Color for half intensity mode */
 	unsigned short	vc_complement_mask;	/* [#] Xor mask for mouse pointer */
-	unsigned short	vc_hi_font_mask;	/* [#] Attribute set for upper 256 chars or font or 0 if not supported */
+	unsigned short	vc_hi_font_mask;	/* [#] Attribute set for upper 256 chars of font or 0 if not supported */
 	unsigned int	vc_x, vc_y;		/* Cursor position */
 	unsigned int	vc_top, vc_bottom;	/* Scrolling region */
 	unsigned int	vc_state;		/* Escape sequence parser state */
@@ -84,6 +86,8 @@
 	unsigned int	vc_bell_duration;	/* Console bell duration */
 	unsigned int	vc_cursor_type;
 	struct vc_data **vc_display_fg;		/* [!] Ptr to var holding fg console for this display */
+	unsigned long	vc_uni_pagedir;
+	unsigned long	*vc_uni_pagedir_loc;  /* [!] Location of uni_pagedir variable for this console */
 	/* additional information is in vt_kern.h */
 };
 
diff -u --recursive --new-file v2.1.111/linux/include/linux/consolemap.h linux/include/linux/consolemap.h
--- v2.1.111/linux/include/linux/consolemap.h	Mon Jun 16 16:36:00 1997
+++ linux/include/linux/consolemap.h	Sun Jul 26 14:40:19 1998
@@ -8,7 +8,8 @@
 #define IBMPC_MAP 2
 #define USER_MAP 3
 
-extern int hashtable_contents_valid;
-extern unsigned char inverse_translate(int glyph);
+struct vc_data;
+
+extern unsigned char inverse_translate(struct vc_data *conp, int glyph);
 extern unsigned short *set_translate(int m);
-extern int conv_uni_to_pc(long ucs);
+extern int conv_uni_to_pc(struct vc_data *conp, long ucs);
diff -u --recursive --new-file v2.1.111/linux/include/linux/fb.h linux/include/linux/fb.h
--- v2.1.111/linux/include/linux/fb.h	Tue Jul 21 00:15:33 1998
+++ linux/include/linux/fb.h	Sun Jul 26 14:40:19 1998
@@ -272,6 +272,8 @@
    struct display_switch *dispsw;   /* low level operations */
    u_short scrollmode;              /* Scroll Method */
    short yscroll;                   /* Hardware scrolling */
+   unsigned char fgshift, bgshift;
+   unsigned short charmask;	    /* 0xff or 0x1ff */
 };
 
 
@@ -333,6 +335,38 @@
 
    /* From here on everything is device dependent */
 };
+
+    /*
+     *  `Generic' versions of the frame buffer device operations
+     */
+
+extern int fbgen_get_fix(struct fb_fix_screeninfo *fix, int con,
+			 struct fb_info *info);
+extern int fbgen_get_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info);
+extern int fbgen_set_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info);
+extern int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info);
+extern int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info);
+extern int fbgen_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *info);
+extern int fbgen_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, unsigned long arg, int con,
+		       struct fb_info *info);
+
+    /*
+     *  Helper functions
+     */
+
+extern int fbgen_do_set_var(struct fb_var_screeninfo *var, int isactive,
+			    struct fb_info_gen *info);
+extern void fbgen_set_disp(int con, struct fb_info_gen *info);
+extern void fbgen_install_cmap(int con, struct fb_info_gen *info);
+extern int fbgen_update_var(int con, struct fb_info *info);
+extern int fbgen_switch(int con, struct fb_info *info);
+extern void fbgen_blank(int blank, struct fb_info *info);
 
 
 struct fb_videomode {
diff -u --recursive --new-file v2.1.111/linux/include/linux/in6.h linux/include/linux/in6.h
--- v2.1.111/linux/include/linux/in6.h	Fri Feb  6 15:33:34 1998
+++ linux/include/linux/in6.h	Sun Jul 26 23:35:56 1998
@@ -126,5 +126,6 @@
 #define IPV6_MULTICAST_LOOP	19
 #define IPV6_ADD_MEMBERSHIP	20
 #define IPV6_DROP_MEMBERSHIP	21
+#define IPV6_ROUTER_ALERT	22
 
 #endif
diff -u --recursive --new-file v2.1.111/linux/include/linux/init.h linux/include/linux/init.h
--- v2.1.111/linux/include/linux/init.h	Wed Apr 23 19:01:29 1997
+++ linux/include/linux/init.h	Tue Jul 28 11:18:47 1998
@@ -9,7 +9,15 @@
  *
  * Usage:
  * For functions:
- * you can surround the whole function declaration 
+ * 
+ * You should add __init immediately before the function name, like:
+ *
+ * static void __init initme(int x, int y)
+ * {
+ *    extern int z; z = x * y;
+ * }
+ *
+ * Depricated: you can surround the whole function declaration 
  * just before function body into __initfunc() macro, like:
  *
  * __initfunc (static void initme(int x, int y))
@@ -17,17 +25,20 @@
  *    extern int z; z = x * y;
  * }
  *
- * if the function has a prototype somewhere, you can also add
+ * If the function has a prototype somewhere, you can also add
  * __init between closing brace of the prototype and semicolon:
  *
  * extern int initialize_foobar_device(int, int, int) __init;
  *
  * For initialized data:
- * you should insert __initdata between the variable name and equal
+ * You should insert __initdata between the variable name and equal
  * sign followed by value, e.g.:
  *
  * static int init_variable __initdata = 0;
  * static char linux_logo[] __initdata = { 0x32, 0x36, ... };
+ *
+ * For initialized data not at file scope, i.e. within a function,
+ * you should use __initlocaldata instead, due to a bug in GCC 2.7.
  */
 
 /*
@@ -46,6 +57,12 @@
 #define __INIT
 #define __FINIT
 #define __INITDATA
+#endif
+
+#if __GNUC__ >= 2 && __GNUC_MINOR__ >= 8
+#define __initlocaldata  __initdata
+#else
+#define __initlocaldata
 #endif
 
 #endif
diff -u --recursive --new-file v2.1.111/linux/include/linux/kd.h linux/include/linux/kd.h
--- v2.1.111/linux/include/linux/kd.h	Sun Jul 26 11:57:19 1998
+++ linux/include/linux/kd.h	Sun Jul 26 14:40:19 1998
@@ -149,6 +149,9 @@
 
 #define KD_FONT_FLAG_GLOBAL		1	/* Change on _all_ consoles */
 #define KD_FONT_FLAG_DONT_RECALC 	2	/* Don't recalculate hw charcell size [compat] */
+#ifdef __KERNEL__
+#define KD_FONT_FLAG_NEW		0x80000000	/* Indicate new KDFONTOP interface, which should be more strict */
+#endif
 
 /* note: 0x4B00-0x4B4E all have had a value at some time;
    don't reuse for the time being */
diff -u --recursive --new-file v2.1.111/linux/include/linux/nfsd/syscall.h linux/include/linux/nfsd/syscall.h
--- v2.1.111/linux/include/linux/nfsd/syscall.h	Fri Feb  6 15:34:24 1998
+++ linux/include/linux/nfsd/syscall.h	Tue Jul 28 13:52:58 1998
@@ -12,6 +12,7 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/socket.h>
+#include <linux/posix_types.h>
 #include <linux/nfsd/const.h>
 #include <linux/nfsd/export.h>
 #include <linux/nfsd/nfsfh.h>
@@ -54,29 +55,29 @@
 struct nfsctl_export {
 	char			ex_client[NFSCLNT_IDMAX+1];
 	char			ex_path[NFS_MAXPATHLEN+1];
-	dev_t			ex_dev;
-	ino_t			ex_ino;
+	__kernel_dev_t		ex_dev;
+	__kernel_ino_t		ex_ino;
 	int			ex_flags;
-	uid_t			ex_anon_uid;
-	gid_t			ex_anon_gid;
+	__kernel_uid_t		ex_anon_uid;
+	__kernel_gid_t		ex_anon_gid;
 };
 
 /* UGIDUPDATE */
 struct nfsctl_uidmap {
 	char *			ug_ident;
-	uid_t			ug_uidbase;
+	__kernel_uid_t		ug_uidbase;
 	int			ug_uidlen;
-	uid_t *			ug_udimap;
-	uid_t			ug_gidbase;
+	__kernel_uid_t *	ug_udimap;
+	__kernel_gid_t		ug_gidbase;
 	int			ug_gidlen;
-	gid_t *			ug_gdimap;
+	__kernel_gid_t *	ug_gdimap;
 };
 
 /* GETFH */
 struct nfsctl_fhparm {
 	struct sockaddr		gf_addr;
-	dev_t			gf_dev;
-	ino_t			gf_ino;
+	__kernel_dev_t		gf_dev;
+	__kernel_ino_t		gf_ino;
 	int			gf_version;
 };
 
diff -u --recursive --new-file v2.1.111/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.1.111/linux/include/linux/proc_fs.h	Tue Jul 21 00:15:33 1998
+++ linux/include/linux/proc_fs.h	Tue Jul 28 13:51:26 1998
@@ -109,6 +109,7 @@
 	PROC_NET_AX25_ROUTE,
 	PROC_NET_AX25,
 	PROC_NET_AX25_CALLS,
+	PROC_NET_BMAC,
 	PROC_NET_NR_NODES,
 	PROC_NET_NR_NEIGH,
 	PROC_NET_NR,
diff -u --recursive --new-file v2.1.111/linux/include/linux/selection.h linux/include/linux/selection.h
--- v2.1.111/linux/include/linux/selection.h	Sun Jul 26 11:57:19 1998
+++ linux/include/linux/selection.h	Tue Jul 28 13:51:45 1998
@@ -40,4 +40,7 @@
 extern void getconsxy(int currcons, char *p);
 extern void putconsxy(int currcons, char *p);
 
+extern u16 vcs_scr_readw(int currcons, u16 *org);
+extern void vcs_scr_writew(int currcons, u16 val, u16 *org);
+
 #endif
diff -u --recursive --new-file v2.1.111/linux/include/linux/simp.h linux/include/linux/simp.h
--- v2.1.111/linux/include/linux/simp.h	Wed Jul 16 19:22:51 1997
+++ linux/include/linux/simp.h	Wed Dec 31 16:00:00 1969
@@ -1,39 +0,0 @@
-/*
- * include/linux/simp.h  -- simple allocator for cached objects
- *
- * This is meant as a faster and simpler (not full-featured) replacement
- * for SLAB, thus the name "simp" :-)
- *
- * (C) 1997 Thomas Schoebel-Theuer
- */
-
-#ifndef SIMP_H
-#define SIMP_H
-
-/* used for constructors / destructors */
-typedef void (*structor)(void *);
-
-/* create an object cache */
-/* positive clearable_offset means the next two pointers at that offset
- * can be internally used for freelist pointers when the object is
- * deallocated / not in use;
- * if there is no space inside the element that can be reused for
- * this purpose, supply -1. Using positive offsets is essential for
- * saving space with very small-sized objects.
- *
- * Note for big-sized objects in the range of whole pages, use
- * the fast Linux page allocator instead, directly.
- */
-extern struct simp * simp_create(char * name, long size,
-				 structor first_ctor, 
-				 structor again_ctor, 
-				 structor dtor);
-
-/* alloc / dealloc routines */
-extern void * simp_alloc(struct simp * simp);
-extern void simp_free(void * objp);
-
-/* garbage collection */
-extern long simp_garbage(void);
-
-#endif
diff -u --recursive --new-file v2.1.111/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v2.1.111/linux/include/linux/skbuff.h	Thu May 14 19:47:44 1998
+++ linux/include/linux/skbuff.h	Tue Jul 28 13:51:27 1998
@@ -151,6 +151,8 @@
 extern int			skb_tailroom(struct sk_buff *skb);
 extern void			skb_reserve(struct sk_buff *skb, unsigned int len);
 extern void 			skb_trim(struct sk_buff *skb, unsigned int len);
+extern void	skb_over_panic(struct sk_buff *skb, int len, void *here);
+extern void	skb_under_panic(struct sk_buff *skb, int len, void *here);
 
 /* Internal */
 extern __inline__ atomic_t *skb_datarefp(struct sk_buff *skb)
@@ -437,10 +439,6 @@
 	return result;
 }
 
-
-extern const char skb_put_errstr[];
-extern const char skb_push_errstr[];
-
 /*
  *	Add data to an sk_buff
  */
@@ -452,9 +450,9 @@
 	skb->len+=len;
 	if(skb->tail>skb->end)
 	{
-		__label__ here;
-		panic(skb_put_errstr,&&here,len);
-here:          ;
+		__label__ here; 
+		skb_over_panic(skb, len, &&here); 
+here:		;
 	}
 	return tmp;
 }
@@ -466,8 +464,8 @@
 	if(skb->data<skb->head)
 	{
 		__label__ here;
-		panic(skb_push_errstr, &&here,len);
-here:          ;
+		skb_under_panic(skb, len, &&here);
+here: 		;
 	}
 	return skb->data;
 }
diff -u --recursive --new-file v2.1.111/linux/include/linux/smp.h linux/include/linux/smp.h
--- v2.1.111/linux/include/linux/smp.h	Fri May  8 23:14:57 1998
+++ linux/include/linux/smp.h	Mon Jul 27 21:25:02 1998
@@ -7,6 +7,7 @@
  */
 
 #ifdef __SMP__
+
 #include <asm/smp.h>
 
 /*
diff -u --recursive --new-file v2.1.111/linux/include/linux/smp_lock.h linux/include/linux/smp_lock.h
--- v2.1.111/linux/include/linux/smp_lock.h	Fri Feb  6 15:32:55 1998
+++ linux/include/linux/smp_lock.h	Tue Jul 28 11:23:30 1998
@@ -1,6 +1,70 @@
 #ifndef __LINUX_SMPLOCK_H
 #define __LINUX_SMPLOCK_H
 
-#include <asm/smp_lock.h>
+#ifndef __SMP__
+
+#define lock_kernel()				do { } while(0)
+#define unlock_kernel()				do { } while(0)
+#define release_kernel_lock(task, cpu)		do { } while(0)
+#define reacquire_kernel_lock(task)		do { } while(0)
+
+#else
+
+#include <linux/interrupt.h>
+#include <asm/spinlock.h>
+
+extern spinlock_t kernel_flag;
+
+/*
+ * Release global kernel lock and global interrupt lock
+ */
+#define release_kernel_lock(task, cpu) \
+do { \
+	if (task->lock_depth) \
+		spin_unlock(&kernel_flag); \
+	release_irqlock(cpu); \
+	__sti(); \
+} while (0)
+
+/*
+ * Re-acquire the kernel lock
+ */
+#define reacquire_kernel_lock(task) \
+do { \
+	if (task->lock_depth) \
+		spin_lock(&kernel_flag); \
+} while (0)
+
+
+/*
+ * Getting the big kernel lock.
+ *
+ * This cannot happen asynchronously,
+ * so we only need to worry about other
+ * CPU's.
+ */
+extern __inline__ void lock_kernel(void)
+{
+	struct task_struct *tsk = current;
+	int lock_depth;
+
+	lock_depth = tsk->lock_depth;
+	tsk->lock_depth = lock_depth+1;
+	if (lock_depth)
+		spin_lock(&kernel_flag);
+}
+
+extern __inline__ void unlock_kernel(void)
+{
+	struct task_struct *tsk = current;
+	int lock_depth;
+
+	lock_depth = tsk->lock_depth-1;
+	tsk->lock_depth = lock_depth;
+	if (!lock_depth)
+		spin_unlock(&kernel_flag);
+}
+
+#endif /* __SMP__ */
 
 #endif
diff -u --recursive --new-file v2.1.111/linux/include/linux/socket.h linux/include/linux/socket.h
--- v2.1.111/linux/include/linux/socket.h	Wed Jun 24 22:54:12 1998
+++ linux/include/linux/socket.h	Sun Jul 26 23:35:56 1998
@@ -183,6 +183,7 @@
 #define PF_ROUTE	AF_ROUTE
 #define PF_PACKET	AF_PACKET
 #define PF_ASH		AF_ASH
+#define PF_ECONET	AF_ECONET
 #define PF_ATMSVC	AF_ATMSVC
 #define PF_SNA		AF_SNA
 
diff -u --recursive --new-file v2.1.111/linux/include/linux/ufs_fs.h linux/include/linux/ufs_fs.h
--- v2.1.111/linux/include/linux/ufs_fs.h	Thu May  7 22:51:55 1998
+++ linux/include/linux/ufs_fs.h	Sun Jul 26 01:20:22 1998
@@ -21,10 +21,6 @@
 #ifndef __LINUX_UFS_FS_H
 #define __LINUX_UFS_FS_H
 
-#undef UFS_HEAVY_DEBUG
-/*#define UFS_HEAVY_DEBUG 1*/
-/* Uncomment the line above when hacking ufs code */
-
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/time.h>
@@ -35,11 +31,15 @@
 #define UFS_SBLOCK 8192
 #define UFS_SBSIZE 8192
 
+#define SECTOR_SIZE 512
+#define SECTOR_BITS 9
 #define UFS_MAGIC 0x00011954
 #define UFS_CIGAM 0x54190100 /* byteswapped MAGIC */
 
-#define UFS_FSIZE 1024
-#define UFS_BSIZE 8192
+#define UFS_BSIZE	8192
+#define UFS_MINBSIZE	4096
+#define UFS_FSIZE	1024
+#define UFS_MAXFRAG	(UFS_BSIZE / UFS_FSIZE)
 
 #define UFS_NDADDR 12
 #define UFS_NINDIR 3
@@ -48,7 +48,13 @@
 #define UFS_DIND_BLOCK	(UFS_NDADDR + 1)
 #define UFS_TIND_BLOCK	(UFS_NDADDR + 2)
 
+#define UFS_NDIR_FRAGMENT (UFS_NDADDR << uspi->s_fpbshift)
+#define UFS_IND_FRAGMENT (UFS_IND_BLOCK << uspi->s_fpbshift)
+#define UFS_DIND_FRAGMENT (UFS_DIND_BLOCK << uspi->s_fpbshift)
+#define UFS_TIND_FRAGMENT (UFS_TIND_BLOCK << uspi->s_fpbshift)
+
 #define UFS_ROOTINO 2
+#define UFS_FIRST_INO (UFS_ROOTINO + 1)
 
 #define UFS_USEEFT  ((__u16)65535)
 
@@ -87,62 +93,109 @@
 #define UFS_HURD		0x00000130
 #define UFS_SUN			0x00000200
 #define UFS_NEXT		0x00000400
-/* we preserve distinction in flavor identification even without difference,
- * because yet-to-be-supported features may introduce difference in the future
- */
-/* last but not least, debug flags */
-#define UFS_DEBUG       	0x01000000
-#define UFS_DEBUG_INODE 	0x02000000
-#define UFS_DEBUG_NAMEI 	0x04000000
-#define UFS_DEBUG_LINKS 	0x08000000
-
-#ifdef UFS_HEAVY_DEBUG
-#  define UFS_DEBUG_INITIAL UFS_DEBUG
-#else
-#  define UFS_DEBUG_INITIAL 0
-#endif
 
 /* fs_inodefmt options */
 #define UFS_42INODEFMT	-1
 #define UFS_44INODEFMT	2
 
-#define UFS_ADDR_PER_BLOCK(sb)		((sb)->u.ufs_sb.s_bsize >> 2)
-#define UFS_ADDR_PER_BLOCK_BITS(sb)	((sb)->u.ufs_sb.s_bshift - 2)
+/*
+ * MINFREE gives the minimum acceptable percentage of file system
+ * blocks which may be free. If the freelist drops below this level
+ * only the superuser may continue to allocate blocks. This may
+ * be set to 0 if no reserve of free blocks is deemed necessary,
+ * however throughput drops by fifty percent if the file system
+ * is run at between 95% and 100% full; thus the minimum default
+ * value of fs_minfree is 5%. However, to get good clustering
+ * performance, 10% is a better choice. hence we use 10% as our
+ * default value. With 10% free space, fragmentation is not a
+ * problem, so we choose to optimize for time.
+ */
+#define UFS_MINFREE         5
+#define UFS_DEFAULTOPT      UFS_OPTTIME
+            
+/*
+ * Turn file system block numbers into disk block addresses.
+ * This maps file system blocks to device size blocks.
+ */
+#define ufs_fsbtodb(uspi, b)	((b) << (uspi)->s_fsbtodb)
+#define	ufs_dbtofsb(uspi, b)	((b) >> (uspi)->s_fsbtodb)
+
+/*
+ * Cylinder group macros to locate things in cylinder groups.
+ * They calc file system addresses of cylinder group data structures.
+ */
+#define	ufs_cgbase(c)	(uspi->s_fpg * (c))
+#define ufs_cgstart(c)	(ufs_cgbase(c)  + uspi->s_cgoffset * ((c) & ~uspi->s_cgmask))
+#define	ufs_cgsblock(c)	(ufs_cgstart(c) + uspi->s_sblkno)	/* super blk */
+#define	ufs_cgcmin(c)	(ufs_cgstart(c) + uspi->s_cblkno)	/* cg block */
+#define	ufs_cgimin(c)	(ufs_cgstart(c) + uspi->s_iblkno)	/* inode blk */
+#define	ufs_cgdmin(c)	(ufs_cgstart(c) + uspi->s_dblkno)	/* 1st data */
+
+/*
+ * Macros for handling inode numbers:
+ *     inode number to file system block offset.
+ *     inode number to cylinder group number.
+ *     inode number to file system block address.
+ */
+#define	ufs_inotocg(x)		((x) / uspi->s_ipg)
+#define	ufs_inotocgoff(x)	((x) % uspi->s_ipg)
+#define	ufs_inotofsba(x)	(ufs_cgimin(ufs_inotocg(x)) + ufs_inotocgoff(x) / uspi->s_inopf)
+#define	ufs_inotofsbo(x)	((x) % uspi->s_inopf)
+
+/*
+ * Give cylinder group number for a file system block.
+ * Give cylinder group block number for a file system block.
+ */
+#define	ufs_dtog(d)	((d) / uspi->s_fpg)
+#define	ufs_dtogd(d)	((d) % uspi->s_fpg)
+
+/*
+ * Compute the cylinder and rotational position of a cyl block addr.
+ */
+#define ufs_cbtocylno(bno) \
+	((bno) * uspi->s_nspf / uspi->s_spc)
+#define ufs_cbtorpos(bno) \
+	((((bno) * uspi->s_nspf % uspi->s_spc / uspi->s_nsect \
+	* uspi->s_trackskew + (bno) * uspi->s_nspf % uspi->s_spc \
+	% uspi->s_nsect * uspi->s_interleave) % uspi->s_nsect \
+	* uspi->s_nrpos) / uspi->s_npsect)
 
-/* Test if the inode number is valid. */
-#define ufs_ino_ok(inode)  ((inode->i_ino < 2) &&  \
-	                    (inode->i_ino > (inode->i_sb->u.ufs_sb.s_ncg * inode->i_sb->u.ufs_sb.s_ipg - 1)))
-
-/* Convert (sb,cg) to the first physical block number for that cg. */
-#define ufs_cgstart(sb, cg)   \
-  (((sb)->u.ufs_sb.s_fpg * (cg)) + (sb)->u.ufs_sb.s_cgoffset * ((cg) & ~((sb)->u.ufs_sb.s_cgmask)))
-
-/* Convert (sb,cg) to the first phys. block number for inodes in that cg. */
-#define ufs_cgimin(sb, cg) (ufs_cgstart((sb), (cg)) + (sb)->u.ufs_sb.s_iblkno)
-#define ufs_cgdmin(sb, cg) (ufs_cgstart((sb), (cg)) + (sb)->u.ufs_sb.s_dblkno)
-
-/* Convert an inode number to a cg number. */
-/* XXX - this can be optimized if s_ipg is a power of 2. */
-#define ufs_ino2cg(inode)  ((inode)->i_ino/(inode)->i_sb->u.ufs_sb.s_ipg)
-
-/* current filesystem state; method depends on flags */
-#define UFS_STATE(usb) \
-		( ((flags&UFS_ST_MASK) == UFS_ST_OLD) \
-                  ? (usb)->fs_u.fs_sun.fs_state /* old normal way */ \
-                  : (usb)->fs_u.fs_44.fs_state /* 4.4BSD way */ )
+/*
+ * The following macros optimize certain frequently calculated
+ * quantities by using shifts and masks in place of divisions
+ * modulos and multiplications.
+ */
+#define ufs_blkoff(loc)		((loc) & uspi->s_qbmask)
+#define ufs_fragoff(loc)	((loc) & uspi->s_qfmask)
+#define ufs_lblktosize(blk)	((blk) << uspi->s_bshift)
+#define ufs_lblkno(loc)		((loc) >> uspi->s_bshift)
+#define ufs_numfrags(loc)	((loc) >> uspi->s_fshift)
+#define ufs_blkroundup(size)	(((size) + uspi->s_qbmask) & uspi->s_bmask)
+#define ufs_fragroundup(size)	(((size) + uspi->s_qfmask) & uspi->s_fmask)
+#define ufs_fragstoblks(frags)	((frags) >> uspi->s_fpbshift)
+#define ufs_blkstofrags(blks)	((blks) << uspi->s_fpbshift)
+#define ufs_fragnum(fsb)	((fsb) & uspi->s_fpbmask)
+#define ufs_blknum(fsb)		((fsb) & ~uspi->s_fpbmask)
 
 #define	UFS_MAXNAMLEN 255
+#define UFS_MAXMNTLEN 512
+#define UFS_MAXCSBUFS 31
+#define UFS_LINK_MAX EXT2_LINK_MAX
 
-#define ufs_lbn(sb, block)		((block) >> (sb)->u.ufs_sb.s_lshift)
-#define ufs_boff(sb, block)		((block) & ~((sb)->u.ufs_sb.s_lmask))
-#define ufs_dbn(sb, block, boff)	((block) + ufs_boff((sb), (boff)))
+/*
+ * UFS_DIR_PAD defines the directory entries boundaries
+ * (must be a multiple of 4)
+ */
+#define UFS_DIR_PAD			4
+#define UFS_DIR_ROUND			(UFS_DIR_PAD - 1)
+#define UFS_DIR_REC_LEN(name_len)	(((name_len) + 1 + 8 + UFS_DIR_ROUND) & ~UFS_DIR_ROUND)
 
 struct ufs_timeval {
 	__s32	tv_sec;
 	__s32	tv_usec;
 };
 
-struct ufs_direct {
+struct ufs_dir_entry {
 	__u32  d_ino;			/* inode number of this entry */
 	__u16  d_reclen;		/* length of this entry */
 	union {
@@ -155,9 +208,6 @@
 	__u8	d_name[UFS_MAXNAMLEN + 1];	/* file name */
 };
 
-#define MAXMNTLEN 512
-#define MAXCSBUFS 32
-
 struct ufs_csum {
 	__u32	cs_ndir;	/* number of directories */
 	__u32	cs_nbfree;	/* number of free blocks */
@@ -168,7 +218,7 @@
 /*
  * This is the actual superblock, as it is laid out on the disk.
  */
-struct ufs_superblock {
+struct ufs_super_block {
 	__u32	fs_link;	/* UNUSED */
 	__u32	fs_rlink;	/* UNUSED */
 	__u32	fs_sblkno;	/* addr of super-block in filesys */
@@ -237,15 +287,18 @@
 	__u8	fs_clean;	/* file system is clean flag */
 	__u8	fs_ronly;	/* mounted read-only flag */
 	__u8	fs_flags;	/* currently unused flag */
-	__u8	fs_fsmnt[MAXMNTLEN];	/* name mounted on */
+	__u8	fs_fsmnt[UFS_MAXMNTLEN];	/* name mounted on */
 /* these fields retain the current block allocation info */
 	__u32	fs_cgrotor;	/* last cg searched */
-	__u32	fs_csp[MAXCSBUFS];	/* list of fs_cs info buffers */
+	__u32	fs_csp[UFS_MAXCSBUFS];	/* list of fs_cs info buffers */
+	__u32	fs_maxcluster;
 	__u32	fs_cpc;		/* cyl per cycle in postbl */
 	__u16	fs_opostbl[16][8];	/* old rotation block list head */	
 	union {
 		struct {
-			__s32	fs_sparecon[55];/* reserved for future constants */
+			__s32	fs_sparecon[53];/* reserved for future constants */
+			__s32	fs_reclaim;
+			__s32	fs_sparecon2[1];
 			__s32	fs_state;	/* file system state time stamp */
 			__u32	fs_qbmask[2];	/* ~usb_bmask */
 			__u32	fs_qfmask[2];	/* ~usb_fmask */
@@ -255,7 +308,7 @@
 			__s32	fs_contigsumsize;/* size of cluster summary array */
 			__s32	fs_maxsymlinklen;/* max length of an internal symlink */
 			__s32	fs_inodefmt;	/* format of on-disk inodes */
-			__u32	fs_maxfilesize[2];/* max representable file size */
+			__u32	fs_maxfilesize[2];	/* max representable file size */
 			__u32	fs_qbmask[2];	/* ~usb_bmask */
 			__u32	fs_qfmask[2];	/* ~usb_fmask */
 			__s32	fs_state;	/* file system state time stamp */
@@ -270,6 +323,59 @@
 };
 
 /*
+ * Preference for optimization.
+ */
+#define UFS_OPTTIME	0	/* minimize allocation time */
+#define UFS_OPTSPACE	1	/* minimize disk fragmentation */
+
+/*
+ * Rotational layout table format types
+ */
+#define UFS_42POSTBLFMT		-1	/* 4.2BSD rotational table format */
+#define UFS_DYNAMICPOSTBLFMT	1	/* dynamic rotational table format */
+
+/*
+ * Convert cylinder group to base address of its global summary info.
+ */
+#define fs_cs(indx) \
+	u.ufs_sb.s_csp[(indx) >> uspi->s_csshift][(indx) & ~uspi->s_csmask]
+
+/*
+ * Cylinder group block for a file system.
+ *
+ * Writable fields in the cylinder group are protected by the associated
+ * super block lock fs->fs_lock.
+ */
+#define	CG_MAGIC	0x090255
+#define ufs_cg_chkmagic(ucg)	(SWAB32((ucg)->cg_magic) == CG_MAGIC)
+
+/*
+ * size of this structure is 172 B
+ */
+struct	ufs_cylinder_group {
+	__u32	cg_link;		/* linked list of cyl groups */
+	__u32	cg_magic;		/* magic number */
+	__u32	cg_time;		/* time last written */
+	__u32	cg_cgx;			/* we are the cgx'th cylinder group */
+	__u16	cg_ncyl;		/* number of cyl's this cg */
+	__u16	cg_niblk;		/* number of inode blocks this cg */
+	__u32	cg_ndblk;		/* number of data blocks this cg */
+	struct	ufs_csum cg_cs;		/* cylinder summary information */
+	__u32	cg_rotor;		/* position of last used block */
+	__u32	cg_frotor;		/* position of last used frag */
+	__u32	cg_irotor;		/* position of last used inode */
+	__u32	cg_frsum[UFS_MAXFRAG];	/* counts of available frags */
+	__u32	cg_btotoff;		/* (__u32) block totals per cylinder */
+	__u32	cg_boff;		/* (short) free block positions */
+	__u32	cg_iusedoff;		/* (char) used inode map */
+	__u32	cg_freeoff;		/* (u_char) free block map */
+	__u32	cg_nextfreeoff;		/* (u_char) next available space */
+	__u32	cg_sparecon[16];	/* reserved for future use */
+	__u8	cg_space[1];		/* space for cylinder group maps */
+/* actually longer */
+};
+
+/*
  * structure of an on-disk inode
  */
 struct ufs_inode {
@@ -277,11 +383,11 @@
 	__u16	ui_nlink;		/*  0x2 */
 	union {
 		struct {
-			__u16	suid;	/*  0x4 */
-			__u16	sgid;	/*  0x6 */
+			__u16	ui_suid;	/*  0x4 */
+			__u16	ui_sgid;	/*  0x6 */
 		} oldids;
-		__u32	inumber;	/*  0x4 lsf: inode number */
-		__u32	author;		/*  0x4 GNU HURD: author */
+		__u32	ui_inumber;	/*  0x4 lsf: inode number */
+		__u32	ui_author;		/*  0x4 GNU HURD: author */
 	} ui_u1;
 	__u64	ui_size;		/*  0x8 */
 	struct ufs_timeval ui_atime;	/* 0x10 access */
@@ -333,43 +439,73 @@
 #define UFS_SF_IMMUTABLE  0x00020000  /* immutable (can't "change") */
 #define UFS_SF_APPEND     0x00040000  /* append-only */
 #define UFS_SF_NOUNLINK   0x00100000  /* can't be removed or renamed */
-    
- 
-#ifdef __KERNEL__
-/*
- * Function prototypes
- */
-
-/* ufs_inode.c */
-extern int ufs_bmap (struct inode *, int);
-extern void ufs_read_inode(struct inode * inode);
-extern void ufs_put_inode(struct inode * inode);
 
-extern void ufs_print_inode (struct inode *);
-
-/* ufs_namei.c */
-extern int ufs_lookup (struct inode *, struct dentry *);
+#ifdef __KERNEL__
 
-/* ufs_super.c */
-extern void ufs_warning (struct super_block *, const char *, const char *, ...)
-        __attribute__ ((format (printf, 3, 4)));
-extern int init_ufs_fs(void);
+/* acl.c */
+extern int ufs_permission (struct inode *, int);
 
-/*
- * Inodes and files operations
- */
+/* balloc.c */
+extern void ufs_free_fragments (struct inode *, unsigned, unsigned);
+extern void ufs_free_blocks (struct inode *, unsigned, unsigned);
+extern unsigned ufs_new_fragments (struct inode *, u32 *, unsigned, unsigned, unsigned, int *);
+
+/* cylinder.c */
+extern struct ufs_cg_private_info * ufs_load_cylinder (struct super_block *, unsigned);
+extern void ufs_put_cylinder (struct super_block *, unsigned);
 
-/* ufs_dir.c */
+/* dir.c */
 extern struct inode_operations ufs_dir_inode_operations;
 extern struct file_operations ufs_dir_operations;
+extern int ufs_check_dir_entry (const char *, struct inode *, struct ufs_dir_entry *, struct buffer_head *, unsigned long);
 
-/* ufs_file.c */
+/* file.c */
 extern struct inode_operations ufs_file_inode_operations;
 extern struct file_operations ufs_file_operations;
 
-/* ufs_symlink.c */
+/* ialloc.c */
+extern void ufs_free_inode (struct inode *inode);
+extern struct inode * ufs_new_inode (const struct inode *, int, int *);
+
+/* inode.c */
+extern int ufs_bmap (struct inode *, int);
+extern void ufs_read_inode (struct inode *);
+extern void ufs_put_inode (struct inode *);
+extern void ufs_write_inode (struct inode *);
+extern int ufs_sync_inode (struct inode *);
+extern void ufs_print_inode (struct inode *);
+extern void ufs_write_inode (struct inode *);
+extern void ufs_delete_inode (struct inode *);
+extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *);
+extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *);
+
+/* namei.c */
+extern int ufs_lookup (struct inode *, struct dentry *);
+extern int ufs_mkdir(struct inode *, struct dentry *, int);
+extern int ufs_rmdir (struct inode *, struct dentry *);
+extern int ufs_unlink (struct inode *, struct dentry *);
+extern int ufs_create (struct inode *, struct dentry *, int);
+extern int ufs_rename (struct inode *, struct dentry *, struct inode *, struct dentry *);
+extern int ufs_mknod (struct inode *, struct dentry *, int, int);
+extern int ufs_symlink (struct inode *, struct dentry *, const char *);
+extern int ufs_link (struct dentry *, struct inode *, struct dentry *);
+        
+/* super.c */
+extern struct super_operations ufs_super_ops;
+extern struct file_system_type ufs_fs_type;
+extern void ufs_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
+extern void ufs_error (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
+extern void ufs_panic (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
+        
+extern int init_ufs_fs(void);
+extern void ufs_write_super (struct super_block *);
+extern void ufs_print_cylinder_stuff(struct ufs_cylinder_group *, __u32);
+
+/* symlink.c */
 extern struct inode_operations ufs_symlink_inode_operations;
-extern struct file_operations ufs_symlink_operations;
+
+/* truncate.c */
+extern void ufs_truncate (struct inode *);
 
 #endif	/* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.111/linux/include/linux/ufs_fs_i.h linux/include/linux/ufs_fs_i.h
--- v2.1.111/linux/include/linux/ufs_fs_i.h	Tue Feb 17 13:12:49 1998
+++ linux/include/linux/ufs_fs_i.h	Sun Jul 26 01:20:22 1998
@@ -8,6 +8,8 @@
  *
  * NeXTstep support added on February 5th 1998 by
  * Niels Kristian Bech Jensen <nkbj@image.dk>.
+ *
+ * write support by Daniel Pirkl <daniel.pirkl@email.cz>
  */
 
 #ifndef _LINUX_UFS_FS_I_H
@@ -16,7 +18,7 @@
 struct ufs_inode_info {
 	union {
 		__u32	i_data[15];
-		__u8	i_symlink[4*15];	/* fast symlink */
+		__u8	i_symlink[4*15];
 	} i_u1;
 	__u64	i_size;
 	__u32	i_flags;
@@ -25,6 +27,8 @@
 	__u32	i_uid;
 	__u32	i_gid;
 	__u32	i_oeftflag;
+	__u16	i_osync;
+	__u32	i_lastfrag;
 };
 
 #endif /* _LINUX_UFS_FS_I_H */
diff -u --recursive --new-file v2.1.111/linux/include/linux/ufs_fs_sb.h linux/include/linux/ufs_fs_sb.h
--- v2.1.111/linux/include/linux/ufs_fs_sb.h	Tue Feb 17 13:12:49 1998
+++ linux/include/linux/ufs_fs_sb.h	Sun Jul 26 01:20:22 1998
@@ -1,4 +1,4 @@
-/*
+/* 
  *  linux/include/linux/ufs_fs_sb.h
  *
  * Copyright (C) 1996
@@ -6,8 +6,10 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * NeXTstep support added on February 5th 1998 by
- * Niels Kristian Bech Jensen <nkbj@image.dk>.
+ * $Id: ufs_fs_sb.h,v 1.8 1998/05/06 12:04:40 jj Exp $
+ *
+ * Write support by Daniel Pirkl (daniel.pirkl@email.cz)
+ * Charles University (Prague), Faculty of Mathematics and Physics
  */
 
 #ifndef __LINUX_UFS_FS_SB_H
@@ -15,27 +17,210 @@
 
 #include <linux/ufs_fs.h>
 
+/*
+ * This structure is used for reading disk structures larger
+ * than the size of fragment.
+ */
+struct ufs_buffer_head {
+	unsigned fragment;			/* first fragment */
+	unsigned count;				/* number of fragments */
+	struct buffer_head * bh[UFS_MAXFRAG];	/* buffers */
+};
+
+struct ufs_cg_private_info {
+	struct ufs_cylinder_group ucg;
+	__u32	c_cgx;		/* number of cylidner group */
+	__u16	c_ncyl;		/* number of cyl's this cg */
+	__u16	c_niblk;	/* number of inode blocks this cg */
+	__u32	c_ndblk;	/* number of data blocks this cg */
+	__u32	c_rotor;	/* position of last used block */
+	__u32	c_frotor;	/* position of last used frag */
+	__u32	c_irotor;	/* position of last used inode */
+	__u32	c_btotoff;	/* (__u32) block totals per cylinder */
+	__u32	c_boff;		/* (short) free block positions */
+	__u32	c_iusedoff;	/* (char) used inode map */
+	__u32	c_freeoff;	/* (u_char) free block map */
+	__u32	c_nextfreeoff;	/* (u_char) next available space */
+};	
+	
+
+struct ufs_sb_private_info {
+	struct ufs_buffer_head s_ubh; /* buffer containing super block */
+	__u32	s_sblkno;	/* offset of super-blocks in filesys */
+	__u32	s_cblkno;	/* offset of cg-block in filesys */
+	__u32	s_iblkno;	/* offset of inode-blocks in filesys */
+	__u32	s_dblkno;	/* offset of first data after cg */
+	__u32	s_cgoffset;	/* cylinder group offset in cylinder */
+	__u32	s_cgmask;	/* used to calc mod fs_ntrak */
+	__u32	s_size;		/* number of blocks (fragments) in fs */
+	__u32	s_dsize;	/* number of data blocks in fs */
+	__u32	s_ncg;		/* number of cylinder groups */
+	__u32	s_bsize;	/* size of basic blocks */
+	__u32	s_fsize;	/* size of fragments */
+	__u32	s_fpb;		/* fragments per block */
+	__u32	s_minfree;	/* minimum percentage of free blocks */
+	__u32	s_bmask;	/* `blkoff'' calc of blk offsets */
+	__u32	s_fmask;	/* s_fsize mask */
+	__u32	s_bshift;	/* `lblkno'' calc of logical blkno */
+	__u32   s_fshift;	/* s_fsize shift */
+	__u32	s_fpbshift;	/* fragments per block shift */
+	__u32	s_fsbtodb;	/* fsbtodb and dbtofsb shift constant */
+	__u32	s_sbsize;	/* actual size of super block */
+	__u32   s_csmask;	/* csum block offset */
+	__u32	s_csshift;	/* csum block number */
+	__u32	s_nindir;	/* value of NINDIR */
+	__u32	s_inopb;	/* value of INOPB */
+	__u32	s_nspf;		/* value of NSPF */
+	__u32	s_npsect;	/* # sectors/track including spares */
+	__u32	s_interleave;	/* hardware sector interleave */
+	__u32	s_trackskew;	/* sector 0 skew, per track */
+	__u32	s_csaddr;	/* blk addr of cyl grp summary area */
+	__u32	s_cssize;	/* size of cyl grp summary area */
+	__u32	s_cgsize;	/* cylinder group size */
+	__u32	s_ntrak;	/* tracks per cylinder */
+	__u32	s_nsect;	/* sectors per track */
+	__u32	s_spc;		/* sectors per cylinder */
+	__u32	s_ipg;		/* inodes per group */
+	__u32	s_fpg;		/* fragments per group */
+	__u32	s_cpc;		/* cyl per cycle in postbl */
+	__s64	s_qbmask;	/* ~usb_bmask */
+	__s64	s_qfmask;	/* ~usb_fmask */
+	__s32	s_postblformat;	/* format of positional layout tables */
+	__s32	s_nrpos;	/* number of rotational positions */
+        __s32	s_postbloff;	/* (__s16) rotation block list head */
+	__s32	s_rotbloff;	/* (__u8) blocks for each rotation */
+
+	__u32	s_fpbmask;	/* fragments per block mask */
+	__u32	s_apb;		/* address per block */
+	__u32	s_2apb;		/* address per block^2 */
+	__u32	s_3apb;		/* address per block^3 */
+	__u32	s_apbmask;	/* address per block mask */
+	__u32	s_apbshift;	/* address per block shift */
+	__u32	s_2apbshift;	/* address per block shift * 2 */
+	__u32	s_3apbshift;	/* address per block shift * 3 */
+	__u32	s_nspfshift;	/* number of sector per fragment shift */
+	__u32	s_nspb;		/* number of sector per block */
+	__u32	s_inopf;	/* inodes per fragment */
+	__u32	s_sbbase;	/* offset of NeXTstep superblock */
+};
+
+
+#define UFS_MAX_GROUP_LOADED 1
+#define UFS_CGNO_EMPTY uspi->s_ncg
+
 struct ufs_sb_info {
-	struct ufs_superblock * s_raw_sb;
-	__u32	s_flags; /* internal flags for UFS code */
-	__u32	s_ncg;	 /* used in ufs_read_inode */
-	__u32	s_ipg;	 /* used in ufs_read_inode */
-	__u32	s_fpg;
-	__u32	s_fsize;
-	__u32	s_fshift;
-	__u32	s_fmask;
-	__u32	s_bsize;
-	__u32	s_bmask;
-	__u32	s_bshift;
-	__u32	s_iblkno;
-	__u32	s_dblkno;
-	__u32	s_cgoffset;
-	__u32	s_cgmask;
-	__u32	s_inopb;
-	__u32	s_lshift;
-	__u32	s_lmask;
-	__u32	s_fsfrag;
-	__u32	s_blockbase;	/* offset of NeXTstep superblock */
+	struct ufs_sb_private_info * s_uspi;	
+	struct ufs_csum	* s_csp[UFS_MAXCSBUFS];
+	int s_rename_lock;
+	struct wait_queue * s_rename_wait;
+	unsigned s_swab;
+	unsigned s_flags;
+	struct buffer_head ** s_ucg;
+	struct ufs_cg_private_info * s_ucpi[UFS_MAX_GROUP_LOADED]; 
+	unsigned s_cgno[UFS_MAX_GROUP_LOADED];
+	unsigned short s_cg_loaded;
+};
+
+/*
+ * Sizes of this structures are:
+ *	ufs_super_block_first	512
+ *	ufs_super_block_second	512
+ *	ufs_super_block_third	356
+ */
+struct ufs_super_block_first {
+	__u32	fs_link;
+	__u32	fs_rlink;
+	__u32	fs_sblkno;
+	__u32	fs_cblkno;
+	__u32	fs_iblkno;
+	__u32	fs_dblkno;
+	__u32	fs_cgoffset;
+	__u32	fs_cgmask;
+	__u32	fs_time;
+	__u32	fs_size;
+	__u32	fs_dsize;
+	__u32	fs_ncg;
+	__u32	fs_bsize;
+	__u32	fs_fsize;
+	__u32	fs_frag;
+	__u32	fs_minfree;
+	__u32	fs_rotdelay;
+	__u32	fs_rps;
+	__u32	fs_bmask;
+	__u32	fs_fmask;
+	__u32	fs_bshift;
+	__u32	fs_fshift;
+	__u32	fs_maxcontig;
+	__u32	fs_maxbpg;
+	__u32	fs_fragshift;
+	__u32	fs_fsbtodb;
+	__u32	fs_sbsize;
+	__u32	fs_csmask;
+	__u32	fs_csshift;
+	__u32	fs_nindir;
+	__u32	fs_inopb;
+	__u32	fs_nspf;
+	__u32	fs_optim;
+	__u32	fs_npsect;
+	__u32	fs_interleave;
+	__u32	fs_trackskew;
+	__u32	fs_id[2];
+	__u32	fs_csaddr;
+	__u32	fs_cssize;
+	__u32	fs_cgsize;
+	__u32	fs_ntrak;
+	__u32	fs_nsect;
+	__u32	fs_spc;
+	__u32	fs_ncyl;
+	__u32	fs_cpg;
+	__u32	fs_ipg;
+	__u32	fs_fpg;
+	struct ufs_csum fs_cstotal;
+	__u8	fs_fmod;
+	__u8	fs_clean;
+	__u8	fs_ronly;
+	__u8	fs_flags;
+	__u8	fs_fsmnt[UFS_MAXMNTLEN - 212];
+
+};
+
+struct ufs_super_block_second {
+	__u8	fs_fsmnt[212];
+	__u32	fs_cgrotor;
+	__u32	fs_csp[UFS_MAXCSBUFS];
+	__u32	fs_maxcluster;
+	__u32	fs_cpc;
+	__u16	fs_opostbl[82];
+};	
+
+struct ufs_super_block_third {
+	__u16	fs_opostbl[46];
+	union {
+		struct {
+			__s32	fs_sparecon[53];/* reserved for future constants */
+			__s32	fs_reclaim;
+			__s32	fs_sparecon2[1];
+			__s32	fs_state;	/* file system state time stamp */
+			__u32	fs_qbmask[2];	/* ~usb_bmask */
+			__u32	fs_qfmask[2];	/* ~usb_fmask */
+		} fs_sun;
+		struct {
+			__s32	fs_sparecon[50];/* reserved for future constants */
+			__s32	fs_contigsumsize;/* size of cluster summary array */
+			__s32	fs_maxsymlinklen;/* max length of an internal symlink */
+			__s32	fs_inodefmt;	/* format of on-disk inodes */
+			__u32	fs_maxfilesize[2];	/* max representable file size */
+			__u32	fs_qbmask[2];	/* ~usb_bmask */
+			__u32	fs_qfmask[2];	/* ~usb_fmask */
+			__s32	fs_state;	/* file system state time stamp */
+		} fs_44;
+	} fs_u;
+	__s32	fs_postblformat;
+	__s32	fs_nrpos;
+	__s32	fs_postbloff;
+	__s32	fs_rotbloff;
+	__s32	fs_magic;
+	__u8	fs_space[1];
 };
 
 #endif /* __LINUX_UFS_FS_SB_H */
diff -u --recursive --new-file v2.1.111/linux/include/linux/vt_kern.h linux/include/linux/vt_kern.h
--- v2.1.111/linux/include/linux/vt_kern.h	Sun Jul 26 11:57:19 1998
+++ linux/include/linux/vt_kern.h	Tue Jul 28 13:51:45 1998
@@ -6,6 +6,7 @@
  * with information needed by the vt package
  */
 
+#include <linux/config.h>
 #include <linux/vt.h>
 
 /*
@@ -16,7 +17,9 @@
  * fixed.  The linux/Documentation directory includes a code snippet
  * to save and restore the text font.
  */
+#ifdef CONFIG_VGA_CONSOLE
 #define BROKEN_GRAPHICS_PROGRAMS 1
+#endif
 
 extern struct vt_struct {
 	int vc_num;				/* The console number */
@@ -66,10 +69,12 @@
 int con_get_trans_old(unsigned char * table);
 int con_set_trans_new(unsigned short * table);
 int con_get_trans_new(unsigned short * table);
-void con_clear_unimap(struct unimapinit *ui);
-int con_set_unimap(ushort ct, struct unipair *list);
-int con_get_unimap(ushort ct, ushort *uct, struct unipair *list);
-void con_set_default_unimap(void);
+int con_clear_unimap(int currcons, struct unimapinit *ui);
+int con_set_unimap(int currcons, ushort ct, struct unipair *list);
+int con_get_unimap(int currcons, ushort ct, ushort *uct, struct unipair *list);
+int con_set_default_unimap(int currcons);
+void con_free_unimap(int currcons);
+void con_protect_unimap(int currcons, int rdonly);
 
 /* vt.c */
 
diff -u --recursive --new-file v2.1.111/linux/include/net/ip6_route.h linux/include/net/ip6_route.h
--- v2.1.111/linux/include/net/ip6_route.h	Thu Mar 26 15:57:06 1998
+++ linux/include/net/ip6_route.h	Sun Jul 26 23:35:57 1998
@@ -100,6 +100,7 @@
 extern int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb);
 extern int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
 extern int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+extern int inet6_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
 
 extern void rt6_ifdown(struct device *dev);
 
diff -u --recursive --new-file v2.1.111/linux/include/net/ipv6.h linux/include/net/ipv6.h
--- v2.1.111/linux/include/net/ipv6.h	Thu May 14 19:47:44 1998
+++ linux/include/net/ipv6.h	Tue Jul 28 13:53:43 1998
@@ -4,7 +4,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>
  *
- *	$Id: ipv6.h,v 1.11 1998/05/07 15:42:46 davem Exp $
+ *	$Id: ipv6.h,v 1.12 1998/07/15 05:05:02 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -117,6 +117,31 @@
 	__u8			nexthdr;
 	__u8			*nhptr;
 };
+
+struct ipv6_tlvtype
+{
+	u8 type;
+	u8 len;
+};
+
+struct ip6_ra_chain
+{
+	struct ip6_ra_chain	*next;
+	struct sock		*sk;
+	int			sel;
+	void			(*destructor)(struct sock *);
+};
+
+extern struct ip6_ra_chain	*ip6_ra_chain;
+
+extern int 			ip6_ra_control(struct sock *sk, int sel,
+					       void (*destructor)(struct sock *));
+
+
+extern int			ip6_call_ra_chain(struct sk_buff *skb, int sel);
+
+extern int 			ip6_dstopt_unknown(struct sk_buff *skb,
+						   struct ipv6_tlvtype *hdr);
 
 extern int			ipv6_routing_header(struct sk_buff **skb, 
 						    struct device *dev,
diff -u --recursive --new-file v2.1.111/linux/include/net/sock.h linux/include/net/sock.h
--- v2.1.111/linux/include/net/sock.h	Tue Jul 21 00:15:33 1998
+++ linux/include/net/sock.h	Tue Jul 28 13:52:02 1998
@@ -469,6 +469,9 @@
 #ifdef CONFIG_NETLINK
 		struct netlink_opt	af_netlink;
 #endif
+#if defined(CONFIG_ECONET) || defined(CONFIG_ECONET_MODULE)
+		struct econet_opt	*af_econet;
+#endif
 	} protinfo;  		
 
 	/* IP 'private area' or will be eventually. */
diff -u --recursive --new-file v2.1.111/linux/include/net/x25.h linux/include/net/x25.h
--- v2.1.111/linux/include/net/x25.h	Sun Nov 30 14:00:39 1997
+++ linux/include/net/x25.h	Sun Jul 26 23:35:57 1998
@@ -147,6 +147,7 @@
 extern struct sock *x25_find_socket(unsigned int, struct x25_neigh *);
 extern void x25_destroy_socket(struct sock *);
 extern int  x25_rx_call_request(struct sk_buff *, struct x25_neigh *, unsigned int);
+extern void x25_kill_by_neigh(struct x25_neigh *);
 
 #include <net/x25call.h>
 
@@ -161,6 +162,7 @@
 extern int  x25_parse_facilities(struct sk_buff *, struct x25_facilities *);
 extern int  x25_create_facilities(unsigned char *, struct x25_facilities *);
 extern int  x25_negotiate_facilities(struct sk_buff *, struct sock *, struct x25_facilities *);
+extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *);
 
 /* x25_in.c */
 extern int  x25_process_rx_frame(struct sock *, struct sk_buff *);
diff -u --recursive --new-file v2.1.111/linux/init/main.c linux/init/main.c
--- v2.1.111/linux/init/main.c	Sun Jul 26 11:57:19 1998
+++ linux/init/main.c	Sun Jul 26 11:54:52 1998
@@ -48,6 +48,10 @@
 #include <linux/dio.h>
 #endif
 
+#ifdef CONFIG_MTRR
+#  include <asm/mtrr.h>
+#endif
+
 /*
  * Versions of gcc older than that listed below may actually compile
  * and link okay, but the end product can have subtle run time bugs.
@@ -1106,11 +1110,21 @@
 #if defined(CONFIG_QUOTA)
 	dquot_init_hash();
 #endif
+	printk("POSIX conformance testing by UNIFIX\n");
+	check_bugs();
+
 #ifdef __SMP__
 	smp_init();
 #endif
-	printk("POSIX conformance testing by UNIFIX\n");
-	check_bugs();
+
+#if defined(CONFIG_MTRR)	/* Do this after SMP initialization */
+/*
+ * We should probably create some architecture-dependent "fixup after
+ * everything is up" style function where this would belong better
+ * than in init/main.c..
+ */
+	mtrr_init ();
+#endif
 
 	sock_init();
 #ifdef CONFIG_SYSCTL
diff -u --recursive --new-file v2.1.111/linux/kernel/exit.c linux/kernel/exit.c
--- v2.1.111/linux/kernel/exit.c	Fri May  8 23:14:57 1998
+++ linux/kernel/exit.c	Mon Jul 27 23:43:59 1998
@@ -46,12 +46,10 @@
 		nr_tasks--;
 		add_free_taskslot(p->tarray_ptr);
 		{
-			unsigned long flags;
-
-			write_lock_irqsave(&tasklist_lock, flags);
+			write_lock_irq(&tasklist_lock);
 			unhash_pid(p);
 			REMOVE_LINKS(p);
-			write_unlock_irqrestore(&tasklist_lock, flags);
+			write_unlock_irq(&tasklist_lock);
 		}
 		release_thread(p);
 		current->cmin_flt += p->min_flt + p->cmin_flt;
@@ -456,12 +454,11 @@
 					__put_user(p->exit_code, stat_addr);
 				retval = p->pid;
 				if (p->p_opptr != p->p_pptr) {
-					/* Note this grabs tasklist_lock
-					 * as a writer... (twice!)
-					 */
+					write_lock_irq(&tasklist_lock);
 					REMOVE_LINKS(p);
 					p->p_pptr = p->p_opptr;
 					SET_LINKS(p);
+					write_unlock_irq(&tasklist_lock);
 					notify_parent(p, SIGCHLD);
 				} else
 					release(p);
diff -u --recursive --new-file v2.1.111/linux/kernel/kmod.c linux/kernel/kmod.c
--- v2.1.111/linux/kernel/kmod.c	Sun Jul 26 11:57:19 1998
+++ linux/kernel/kmod.c	Mon Jul 27 18:20:10 1998
@@ -14,7 +14,8 @@
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/unistd.h>
-#include <asm/smp_lock.h>
+#include <linux/smp_lock.h>
+
 #include <asm/uaccess.h>
 
 /*
diff -u --recursive --new-file v2.1.111/linux/kernel/sched.c linux/kernel/sched.c
--- v2.1.111/linux/kernel/sched.c	Sun Jul 26 11:57:19 1998
+++ linux/kernel/sched.c	Mon Jul 27 22:53:40 1998
@@ -105,10 +105,19 @@
 
 static inline void reschedule_idle(struct task_struct * p)
 {
+
 	/*
 	 * For SMP, we try to see if the CPU the task used
 	 * to run on is idle..
 	 */
+#if 0
+	/*
+	 * Disable this for now. Ingo has some interesting
+	 * code that looks too complex, and I have some ideas,
+	 * but in the meantime.. One problem is that "wakeup()"
+	 * can be (and is) called before we've even initialized
+	 * SMP completely, so..
+	 */
 #ifdef __SMP__
 	int want_cpu = p->processor;
 
@@ -132,6 +141,7 @@
 		} while (--i > 0);
 	}
 #endif
+#endif
 	if (p->policy != SCHED_OTHER || p->counter > current->counter + 3)
 		current->need_resched = 1;	
 }
@@ -437,16 +447,15 @@
  */
 asmlinkage void schedule(void)
 {
-	int lock_depth;
 	struct task_struct * prev, * next;
 	unsigned long timeout;
 	int this_cpu;
 
 	prev = current;
-	this_cpu = smp_processor_id();
+	this_cpu = prev->processor;
 	if (in_interrupt())
 		goto scheduling_in_interrupt;
-	release_kernel_lock(prev, this_cpu, lock_depth);
+	release_kernel_lock(prev, this_cpu);
 	if (bh_active & bh_mask)
 		do_bottom_half();
 
@@ -454,6 +463,7 @@
 	spin_lock_irq(&runqueue_lock);
 
 	/* move an exhausted RR process to be last.. */
+	prev->need_resched = 0;
 	if (!prev->counter && prev->policy == SCHED_RR) {
 		prev->counter = prev->priority;
 		move_last_runqueue(prev);
@@ -551,8 +561,7 @@
 	 * switched into it (from an even more "previous"
 	 * prev)
 	 */
-	prev->need_resched = 0;
-	reacquire_kernel_lock(prev, smp_processor_id(), lock_depth);
+	reacquire_kernel_lock(prev);
 	return;
 
 scheduling_in_interrupt:
diff -u --recursive --new-file v2.1.111/linux/mm/memory.c linux/mm/memory.c
--- v2.1.111/linux/mm/memory.c	Wed Jul  1 19:38:57 1998
+++ linux/mm/memory.c	Sun Jul 26 13:55:43 1998
@@ -127,16 +127,23 @@
  */
 void clear_page_tables(struct task_struct * tsk)
 {
+	pgd_t * page_dir = tsk->mm->pgd;
 	int i;
-	pgd_t * page_dir;
 
-	page_dir = tsk->mm->pgd;
-	if (!page_dir || page_dir == swapper_pg_dir) {
-		printk("%s trying to clear kernel page-directory: not good\n", tsk->comm);
-		return;
-	}
+	if (!page_dir || page_dir == swapper_pg_dir)
+		goto out_bad;
 	for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
 		free_one_pgd(page_dir + i);
+
+	/* keep the page table cache within bounds */
+	check_pgt_cache();
+	return;
+
+out_bad:
+	printk(KERN_ERR 
+		"clear_page_tables: %s trying to clear kernel pgd\n",
+		tsk->comm);
+	return;
 }
 
 /*
@@ -146,19 +153,26 @@
  */
 void free_page_tables(struct mm_struct * mm)
 {
+	pgd_t * page_dir = mm->pgd;
 	int i;
-	pgd_t * page_dir;
 
-	page_dir = mm->pgd;
-	if (page_dir) {
-		if (page_dir == swapper_pg_dir) {
-			printk("free_page_tables: Trying to free kernel pgd\n");
-			return;
-		}
-		for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
-			free_one_pgd(page_dir + i);
-		pgd_free(page_dir);
-	}
+	if (!page_dir)
+		goto out;
+	if (page_dir == swapper_pg_dir)
+		goto out_bad;
+	for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
+		free_one_pgd(page_dir + i);
+	pgd_free(page_dir);
+
+	/* keep the page table cache within bounds */
+	check_pgt_cache();
+out:
+	return;
+
+out_bad:
+	printk(KERN_ERR
+		"free_page_tables: Trying to free kernel pgd\n");
+	return;
 }
 
 int new_page_tables(struct task_struct * tsk)
diff -u --recursive --new-file v2.1.111/linux/mm/mmap.c linux/mm/mmap.c
--- v2.1.111/linux/mm/mmap.c	Sun Jul 26 11:57:20 1998
+++ linux/mm/mmap.c	Sun Jul 26 13:51:42 1998
@@ -196,9 +196,14 @@
 			if ((prot & PROT_WRITE) && !(file->f_mode & 2))
 				return -EACCES;
 
+			/* Make sure we don't allow writing to an append-only file.. */
+			if (IS_APPEND(file->f_dentry->d_inode) && (file->f_mode & 2))
+				return -EACCES;
+
 			/* make sure there are no mandatory locks on the file. */
 			if (locks_verify_locked(file->f_dentry->d_inode))
 				return -EAGAIN;
+
 			/* fall through */
 		case MAP_PRIVATE:
 			if (!(file->f_mode & 1))
diff -u --recursive --new-file v2.1.111/linux/mm/simp.c linux/mm/simp.c
--- v2.1.111/linux/mm/simp.c	Wed Apr  8 19:36:29 1998
+++ linux/mm/simp.c	Wed Dec 31 16:00:00 1969
@@ -1,435 +0,0 @@
-#define NULL 0
-/*
- * mm/simp.c  -- simple allocator for cached objects
- *
- * (C) 1997 Thomas Schoebel-Theuer
- */
-
-#include <linux/simp.h>
-#include <linux/tasks.h>
-#include <linux/smp.h>
-#include <linux/mm.h>
-#include <asm/spinlock.h>
-
-/* The next two defines can be independently enabled for debugging */
-/*#define DEBUG*/
-/*#define DEAD_BEEF*/
-
-#ifdef DEAD_BEEF
-#define DEBUG_BEEF 1
-#else
-#define DEBUG_BEEF 0
-#endif
-
-#ifdef __SMP__
-#define NR_PROCESSORS  NR_CPUS
-#define GLOBAL_SIZE CHUNK_SIZE
-#else
-#define NR_PROCESSORS  1
-#define GLOBAL_SIZE PAGE_SIZE
-#endif
-
-#define POSTBUFFER_SIZE 63
-#define ORDER 2
-#define CHUNK_SIZE (PAGE_SIZE*(1<<ORDER))
-#define CHUNK_BASE(ptr) (struct header*)(((unsigned long)(ptr)) & ~(CHUNK_SIZE-1))
-#define CHUNK_END(hdr) (void**)((char*)(hdr) + CHUNK_SIZE)
-
-#define COLOR_INCREMENT (8*sizeof(void*)) /* should be 1 cache line */
-#define ALIGN_CACHE(adr) ((((((unsigned long)adr) - 1) / COLOR_INCREMENT) + 1) * COLOR_INCREMENT)
-#define HEADER_SIZE ALIGN_CACHE(sizeof(struct header))
-#define ELEM_SIZE ALIGN_CACHE(sizeof(struct elem))
-#define FILL_TYPE(name,wrongsize) char name[ALIGN_CACHE(wrongsize)-(wrongsize)]
-
-#define MAX_SIMPS ((GLOBAL_SIZE / sizeof(struct simp)) - 1)
-
-struct header { /* this is at the beginning of each memory region */
-	/* 1st cache line */
-	void ** index;
-	void ** fresh;
-	struct simp * father;
-	void ** emptypos;
-	struct header * next;
-	structor again_ctor;
-	structor first_ctor;
-	void * fill[1];
-#ifdef DEBUG
-	/* 2nd cache line */
-	char magic[32];
-#endif
-};
-
-struct per_processor {
-	void ** buffer_pos;
-	void * postbuffer[POSTBUFFER_SIZE];
-};
-
-struct simp {
-	/* 1st cache lines */
-	struct per_processor private[NR_PROCESSORS];
-	/* next cache line */
-	struct header * usable_list;
-	spinlock_t lock;
-	/* This value is negative on Alpha SMP.  */
-	/* char fill[sizeof(void*) - sizeof(spinlock_t)]; */
-	long real_size;
-	long max_elems;
-	structor again_ctor;
-	structor first_ctor;
-	structor dtor;
-	long fill2;
-	/* next cache line */
-	long create_offset;
-	long color;
-	long max_color;
-	long size;
-	long fill3[4];
-	/* next cache line */
-	char name[32];
-};
-
-struct global_data {
-	/* 1st cache line */
-	long changed_flag;
-	long nr_simps;
-	spinlock_t lock;
-	char fill[(6+8)*sizeof(void*)+sizeof(void*)-sizeof(spinlock_t)];
-	/* rest */
-	struct simp simps[MAX_SIMPS];
-};
-
-static struct global_data * global = NULL;
-
-#ifdef DEBUG
-static char global_magic[32] = "SIMP header SdC581oi9rY20051962\n";
-#endif
-
-struct simp * simp_create(char * name, long size,
-			  structor first_ctor, 
-			  structor again_ctor, 
-			  structor dtor)
-{
-	struct simp * simp;
-	long fraction;
-	long real_size;
-	int cpu;
-
-	if(!global) {
-#ifdef __SMP__
-		global = (struct global_data*)__get_free_pages(GFP_KERNEL, ORDER);
-		memset(global, 0, CHUNK_SIZE);
-#else
-		global = (struct global_data*)get_free_page(GFP_KERNEL);
-#endif
-		spin_lock_init(&global->lock);
-	}
-
-	spin_lock(&global->lock);
-	simp = &global->simps[global->nr_simps++];
-	spin_unlock(&global->lock);
-
-	if(global->nr_simps >= MAX_SIMPS) {
-		printk("SIMP: too many simps allocated\n");
-		return NULL;
-	}
-	memset(simp, 0, sizeof(struct simp));
-	spin_lock_init(&simp->lock);
-	strncpy(simp->name, name, 15);
-	simp->size = size;
-	simp->real_size = real_size = ALIGN_CACHE(size);
-	/* allow aggregation of very small objects in 2-power fractions of
-	 * cachelines */
-	fraction = COLOR_INCREMENT / 2;
-	while(size <= fraction && fraction >= sizeof(void*)) {
-		simp->real_size = fraction;
-		fraction >>= 1;
-	}
-	simp->first_ctor = first_ctor;
-	simp->again_ctor = again_ctor;
-	simp->dtor = dtor;
-	
-	real_size += sizeof(void*);
-	simp->max_elems = (CHUNK_SIZE - HEADER_SIZE) / real_size;
-	simp->max_color = (CHUNK_SIZE - HEADER_SIZE) % real_size;
-	for(cpu = 0; cpu < NR_PROCESSORS; cpu++) {
-		struct per_processor * private = &simp->private[cpu];
-		private->buffer_pos = private->postbuffer;
-	}
-	return simp;
-}
-
-/* Do *not* inline this, it clobbers too many registers... */
-static void alloc_header(struct simp * simp)
-{
-	struct header * hdr;
-	char * ptr;
-	void ** index;
-	long count;
-
-	spin_unlock(&simp->lock);
-	for(;;) {
-		hdr = (struct header*)__get_free_pages(GFP_KERNEL, ORDER);
-		if(hdr)
-			break;
-		if(!simp_garbage())
-			return;
-	}
-#ifdef DEBUG
-	if(CHUNK_BASE(hdr) != hdr)
-		panic("simp: bad kernel page alignment");
-#endif
-
-	memset(hdr, 0, HEADER_SIZE);
-#ifdef DEBUG
-	memcpy(hdr->magic, global_magic, sizeof(global_magic));
-#endif
-	hdr->father = simp;
-	hdr->again_ctor = simp->again_ctor;
-	hdr->first_ctor = simp->first_ctor;
-	
-	/* note: races on simp->color don't produce any error :-) */
-	ptr = ((char*)hdr) + HEADER_SIZE + simp->color;
-	index = CHUNK_END(hdr);
-	for(count = 0; count < simp->max_elems; count++) {
-		*--index = ptr;
-		ptr += simp->real_size;
-		/* note: constructors are not called here in bunch but
-		 * instead at each single simp_alloc(), in order
-		 * to maximize chances that the cache will be
-		 * polluted after a simp_alloc() anyway,
-		 * and not here. */
-	}
-	hdr->index = hdr->fresh = hdr->emptypos = index;
-
-	spin_lock(&simp->lock);
-	simp->color += COLOR_INCREMENT;
-	if(simp->color >= simp->max_color)
-		simp->color = 0;
-	hdr->next = simp->usable_list;
-	simp->usable_list = hdr;
-}
-
-/* current x86 memcpy() is horribly moving around registers for nothing,
- * is doing unnecessary work if the size is dividable by a power-of-two,
- * and it clobbers way too many registers.
- * This results in nearly any other register being transfered to stack.
- * Fixing this would be a major win for the whole kernel!
- */
-static void ** bunch_alloc(struct simp * simp, void ** buffer)
-{
-	struct header * hdr;
-	void ** index;
-	void ** to;
-	void ** end;
-	structor todo;
-	long length;
-
-	spin_lock(&simp->lock);
-	hdr = simp->usable_list;
-	if(!hdr) {
-		alloc_header(simp);
-		hdr = simp->usable_list;
-		if(!hdr) {
-			spin_unlock(&simp->lock);
-			*buffer = NULL;
-			return buffer+1;
-		}
-	}
-	
-	index = hdr->index;
-	end = hdr->fresh;
-	todo = hdr->again_ctor;
-	if(index == end) {
-		end = CHUNK_END(hdr);
-		todo = hdr->first_ctor;
-	}
-	to = index + POSTBUFFER_SIZE/2;
-	if(to >= end) {
-		to = end;
-		if(to == CHUNK_END(hdr)) {
-			simp->usable_list = hdr->next;
-			hdr->next = NULL;
-		}
-	}
-	if(to > hdr->fresh)
-		hdr->fresh = to;
-	hdr->index = to;
-	length = ((unsigned long)to) - (unsigned long)index;
-	to = buffer + (length/sizeof(void**));
-
-	memcpy(buffer, index, length);
-
-	spin_unlock(&simp->lock);
-
-	if(todo) {
-		do {
-			todo(*buffer++);
-		} while(buffer < to);
-	}
-	return to;
-}
-
-void * simp_alloc(struct simp * simp)
-{
-#ifdef __SMP__
-	const long cpu = smp_processor_id();
-	struct per_processor * priv = &simp->private[cpu];
-#else
-#define priv (&simp->private[0]) /*fool gcc to use no extra register*/
-#endif
-	void ** buffer_pos = priv->buffer_pos;
-	void * res;
-
-	if(buffer_pos == priv->postbuffer) {
-		buffer_pos = bunch_alloc(simp, buffer_pos);
-	}
-	buffer_pos--;
-	res = *buffer_pos;
-	priv->buffer_pos = buffer_pos;
-	return res;
-}
-
-#ifdef DEBUG
-long check_header(struct header * hdr, void * ptr)
-{
-	void ** test;
-
-	if(!hdr) {
-		printk("SIMP: simp_free() with NULL pointer\n");
-		return 1;
-	}
-	if(strncmp(hdr->magic, global_magic, 32)) {
-		printk("SIMP: simpe_free() with bad ptr %p, or header corruption\n", ptr);
-		return 1;
-	}
-	/* This is brute force, but I don't want to pay for any
-	 * overhead if debugging is not enabled, in particular
-	 * no space overhead for keeping hashtables etc. */
-	test = hdr->index;
-	while(test < CHUNK_END(hdr)) {
-		if(*test++ == ptr) {
-			printk("SIMP: trying to simp_free(%p) again\n", ptr);
-			return 1;
-		}
-	}
-	return 0;
-}
-#endif
-
-static void ** bunch_free(struct simp * simp, void ** buffer)
-{
-	void ** stop;
-
-	stop = buffer - POSTBUFFER_SIZE/3;
-
-	spin_lock(&simp->lock);
-	while(buffer > stop) {
-		void * elem = buffer[-1];
-		struct header * hdr = CHUNK_BASE(elem);
-		void ** index = hdr->index;
-		index--;
-		hdr->index = index;
-		*index = elem;
-		if(!hdr->next) {
-			hdr->next = simp->usable_list;
-			simp->usable_list = hdr;
-		}
-
-		buffer -= 2;
-		elem = *buffer;
-		hdr = CHUNK_BASE(elem);
-		index = hdr->index;
-		index--;
-		hdr->index = index;
-		*index = elem;
-		if(!hdr->next) {
-			hdr->next = simp->usable_list;
-			simp->usable_list = hdr;
-		}
-	}
-	spin_unlock(&simp->lock);
-	global->changed_flag = 1;
-	return buffer;
-}
-
-void simp_free(void * objp)
-{
-	struct header * hdr;
-	void ** buffer_pos;
-	struct per_processor * private;
-#ifdef __SMP__
-	const long cpu = smp_processor_id();
-#else
-	const long cpu = 0;
-#endif
-
-	hdr = CHUNK_BASE(objp);
-#ifdef DEBUG
-	if(check_header(hdr, objp))
-		return;
-#endif
-
-	private = &hdr->father->private[cpu];
-	buffer_pos = private->buffer_pos;
-	if(buffer_pos >= private->postbuffer+POSTBUFFER_SIZE) {
-		buffer_pos = bunch_free(hdr->father, buffer_pos);
-	}
-
-	*buffer_pos++ = objp;
-	private->buffer_pos = buffer_pos;
-
-#ifdef DEAD_BEEF
-	{
-		unsigned int * ptr = (unsigned int*)objp;
-		int count = (hdr->father->real_size - ELEM_SIZE) / sizeof(unsigned int);
-		while(count--)
-			*ptr++ = 0xdeadbeef;
-	}
-#endif
-}
-
-long simp_garbage(void)
-{
-	int i;
-	int res;
-
-	if(!global->changed_flag)
-		return 0; /* shortcut */
-	/* Note: costs do not matter here. Any heavy thrashing of
-	 * simp chunks that could be caused by pools stealing each
-	 * other's memory has to be considered a BUG :-)
-	 * Simply avoid memory shortages by conservative allocating
-	 * policies.
-	 */
-	global->changed_flag = 0;
-	res = 0;
-	for(i = 0; i < global->nr_simps; i++) {
-		struct simp * simp = &global->simps[i];
-		struct header ** base = &simp->usable_list;
-		struct header * del;
-
-		spin_lock(&simp->lock);
-		del = *base;
-		while(del) {
-			if(del->index == del->emptypos) {
-				if(simp->dtor) {
-					void ** ptr = del->index;
-					while(ptr < CHUNK_END(del)) {
-						simp->dtor(*ptr++);
-					}
-				}
-				*base = del->next;
-#ifdef DEBUG
-				memset(del, 0, CHUNK_SIZE);
-#endif
-				free_pages((unsigned long)del, ORDER);
-				res++;
-			} else
-				base = &del->next;
-			del = *base;
-		}
-		spin_unlock(&simp->lock);
-	}
-	return res;
-}
-
diff -u --recursive --new-file v2.1.111/linux/mm/slab.c linux/mm/slab.c
--- v2.1.111/linux/mm/slab.c	Sun Jul 26 11:57:20 1998
+++ linux/mm/slab.c	Mon Jul 27 18:20:25 1998
@@ -109,7 +109,6 @@
 
 #include	<asm/system.h>
 #include	<asm/atomic.h>
-#include	<asm/smp_lock.h>
 #include	<asm/spinlock.h>
 
 /* If there is a different PAGE_SIZE around, and it works with this allocator,
diff -u --recursive --new-file v2.1.111/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.1.111/linux/mm/swapfile.c	Wed Jun 24 22:54:14 1998
+++ linux/mm/swapfile.c	Sun Jul 26 11:46:46 1998
@@ -532,6 +532,7 @@
 		error = blkdev_open(swap_dentry->d_inode, &filp);
 		if (error)
 			goto bad_swap_2;
+		set_blocksize(p->swap_device, PAGE_SIZE);
 		error = -ENODEV;
 		if (!p->swap_device ||
 		    (blk_size[MAJOR(p->swap_device)] &&
diff -u --recursive --new-file v2.1.111/linux/net/Makefile linux/net/Makefile
--- v2.1.111/linux/net/Makefile	Sun Nov 30 14:00:39 1997
+++ linux/net/Makefile	Sun Jul 26 23:35:57 1998
@@ -9,7 +9,8 @@
 
 MOD_SUB_DIRS := ipv4
 ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \
-		netrom rose lapb x25 wanrouter netlink sched packet sunrpc #decnet
+		netrom rose lapb x25 wanrouter netlink sched packet sunrpc \
+		econet #decnet
 SUB_DIRS     := core ethernet sched
 MOD_LIST_NAME := NET_MISC_MODULES
 
@@ -137,6 +138,14 @@
 else
   ifeq ($(CONFIG_DECNET),m)
   MOD_SUB_DIRS += decnet
+  endif
+endif
+
+ifeq ($(CONFIG_ECONET),y)
+SUB_DIRS += econet
+else
+  ifeq ($(CONFIG_ECONET),m)
+  MOD_SUB_DIRS += econet
   endif
 endif
 
diff -u --recursive --new-file v2.1.111/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v2.1.111/linux/net/ax25/af_ax25.c	Sun Jul 26 11:57:20 1998
+++ linux/net/ax25/af_ax25.c	Sun Jul 26 23:35:57 1998
@@ -91,7 +91,7 @@
  *			Jonathan(G4KLX)		Support for packet forwarding.
  *	AX.25 036	Jonathan(G4KLX)		Major restructuring.
  *			Joerg(DL1BKE)		Fixed DAMA Slave.
- *			Jonathan(G4KLX)		Fix widlcard listen parameter setting.
+ *			Jonathan(G4KLX)		Fix wildcard listen parameter setting.
  *	AX.25 037	Jonathan(G4KLX)		New timer architecture.
  *      AX.25 038       Matthias(DG2FEF)        Small fixes to the syscall interface to make kernel
  *                                              independent of AX25_MAX_DIGIS used by applications.
diff -u --recursive --new-file v2.1.111/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- v2.1.111/linux/net/core/skbuff.c	Thu May 14 19:47:44 1998
+++ linux/net/core/skbuff.c	Sun Jul 26 23:35:57 1998
@@ -77,11 +77,22 @@
 static kmem_cache_t *skbuff_head_cache;
 
 /*
- *	Strings we don't want inline's duplicating
+ *	Keep out-of-line to prevent kernel bloat.
+ *	__builtin_return_address is not used because it is not always
+ *	reliable. 
  */
- 
-const char skb_push_errstr[]="skpush:under: %p:%d";
-const char skb_put_errstr[] ="skput:over: %p:%d";
+
+void skb_over_panic(struct sk_buff *skb, int sz, void *here)
+{
+	panic("skput:over: %p:%d put:%d dev:%s", 
+		here, skb->len, sz, skb->dev ? skb->dev->name : "<NULL>");
+}
+
+void skb_under_panic(struct sk_buff *skb, int sz, void *here)
+{
+        panic("skput:over: %p:%d put:%d dev:%s",
+                here, skb->len, sz, skb->dev ? skb->dev->name : "<NULL>");
+}
 
 void show_net_buffers(void)
 {
diff -u --recursive --new-file v2.1.111/linux/net/core/sock.c linux/net/core/sock.c
--- v2.1.111/linux/net/core/sock.c	Tue Jun 23 10:01:30 1998
+++ linux/net/core/sock.c	Sun Jul 26 23:35:57 1998
@@ -105,6 +105,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/poll.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -212,7 +213,7 @@
 			   are treated in BSD as hints */
 			   
 			if (val > sysctl_wmem_max)
-				return 0;
+				val = sysctl_wmem_max;
 
 			sk->sndbuf = max(val*2,2048);
 
@@ -230,7 +231,7 @@
 			   are treated in BSD as hints */
 			  
 			if (val > sysctl_rmem_max)
-				return 0;
+				val = sysctl_rmem_max;
 
 			/* FIXME: is this lower bound the right one? */
 			sk->rcvbuf = max(val*2,256);
@@ -495,10 +496,11 @@
 	kmem_cache_free(sk_cachep, sk);
 }
 
-void sk_init(void)
+__initfunc(void sk_init(void))
 {
 	sk_cachep = kmem_cache_create("sock", sizeof(struct sock), 0,
 				      SLAB_HWCACHE_ALIGN, 0, 0);
+
 }
 
 /*
diff -u --recursive --new-file v2.1.111/linux/net/econet/econet.c linux/net/econet/econet.c
--- v2.1.111/linux/net/econet/econet.c	Fri May  8 23:14:57 1998
+++ linux/net/econet/econet.c	Sun Jul 26 23:35:57 1998
@@ -738,8 +738,8 @@
 	econet_release,
 	econet_bind,
 	sock_no_connect,
-	NULL,
-	NULL,
+	sock_no_socketpair,
+	sock_no_accept,
 	econet_getname, 
 	datagram_poll,
 	econet_ioctl,
diff -u --recursive --new-file v2.1.111/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.1.111/linux/net/ipv4/arp.c	Thu May 14 19:47:44 1998
+++ linux/net/ipv4/arp.c	Sun Jul 26 23:35:57 1998
@@ -1,6 +1,6 @@
 /* linux/net/inet/arp.c
  *
- * Version:	$Id: arp.c,v 1.66 1998/05/08 01:54:55 davem Exp $
+ * Version:	$Id: arp.c,v 1.67 1998/06/19 13:22:31 davem Exp $
  *
  * Copyright (C) 1994 by Florian  La Roche
  *
@@ -15,7 +15,7 @@
  * 2 of the License, or (at your option) any later version.
  *
  * Fixes:
- *		Alan Cox	:	Removed the ethernet assumptions in 
+ *		Alan Cox	:	Removed the Ethernet assumptions in 
  *					Florian's code
  *		Alan Cox	:	Fixed some small errors in the ARP 
  *					logic
@@ -230,7 +230,7 @@
 		neigh->ops = &arp_direct_ops;
 		neigh->output = neigh->ops->queue_xmit;
 	} else {
-		/* Good devices (checked by reading texts, but only ethernet is
+		/* Good devices (checked by reading texts, but only Ethernet is
 		   tested)
 
 		   ARPHRD_ETHER: (ethernet, apfddi)
@@ -240,7 +240,7 @@
 		   ARPHRD_ARCNET:
 		   etc. etc. etc.
 
-		   ARPHRD_IPDDP will also work, if author repaires it.
+		   ARPHRD_IPDDP will also work, if author repairs it.
 		   I did not it, because this driver does not work even
 		   in old paradigm.
 		 */
@@ -1099,7 +1099,7 @@
 #ifdef CONFIG_AX25_MODULE
 
 /*
- *	ax25 -> ascii conversion
+ *	ax25 -> ASCII conversion
  */
 char *ax2asc(ax25_address *a)
 {
diff -u --recursive --new-file v2.1.111/linux/net/ipv4/fib_hash.c linux/net/ipv4/fib_hash.c
--- v2.1.111/linux/net/ipv4/fib_hash.c	Tue Mar 17 22:18:16 1998
+++ linux/net/ipv4/fib_hash.c	Sun Jul 26 23:35:57 1998
@@ -5,7 +5,7 @@
  *
  *		IPv4 FIB: lookup engine and maintenance routines.
  *
- * Version:	$Id: fib_hash.c,v 1.3 1998/03/08 05:56:16 davem Exp $
+ * Version:	$Id: fib_hash.c,v 1.4 1998/07/15 05:05:08 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -274,7 +274,7 @@
 #endif
 			    ) {
 				if (matched)
-					return 1;
+					break;
 				continue;
 			}
 			matched = 1;
diff -u --recursive --new-file v2.1.111/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.1.111/linux/net/ipv4/icmp.c	Tue Jun 23 10:01:30 1998
+++ linux/net/ipv4/icmp.c	Sun Jul 26 23:35:57 1998
@@ -3,7 +3,7 @@
  *	
  *		Alan Cox, <alan@cymru.net>
  *
- *	Version: $Id: icmp.c,v 1.43 1998/06/11 03:15:43 davem Exp $
+ *	Version: $Id: icmp.c,v 1.44 1998/06/16 04:38:27 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
diff -u --recursive --new-file v2.1.111/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- v2.1.111/linux/net/ipv4/ip_fragment.c	Tue Jun 23 10:01:30 1998
+++ linux/net/ipv4/ip_fragment.c	Sun Jul 26 23:35:57 1998
@@ -5,7 +5,7 @@
  *
  *		The IP fragmentation functionality.
  *		
- * Version:	$Id: ip_fragment.c,v 1.37 1998/06/10 00:22:00 davem Exp $
+ * Version:	$Id: ip_fragment.c,v 1.38 1998/06/16 04:38:29 davem Exp $
  *
  * Authors:	Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
  *		Alan Cox <Alan.Cox@linux.org>
diff -u --recursive --new-file v2.1.111/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v2.1.111/linux/net/ipv4/ip_output.c	Tue Jun 23 10:01:31 1998
+++ linux/net/ipv4/ip_output.c	Sun Jul 26 23:35:57 1998
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) output module.
  *
- * Version:	$Id: ip_output.c,v 1.58 1998/05/15 15:21:36 davem Exp $
+ * Version:	$Id: ip_output.c,v 1.59 1998/07/15 05:05:15 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -814,7 +814,7 @@
 		 * will inherit fixed options.
 		 */
 		if (offset == 0)
-			ip_options_fragment(skb2);
+			ip_options_fragment(skb);
 
 		/*
 		 *	Added AC : If we are fragmenting a fragment that's not the
diff -u --recursive --new-file v2.1.111/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c
--- v2.1.111/linux/net/ipv4/ip_sockglue.c	Thu May 14 19:47:44 1998
+++ linux/net/ipv4/ip_sockglue.c	Sun Jul 26 23:35:57 1998
@@ -5,7 +5,7 @@
  *
  *		The IP to API glue.
  *		
- * Version:	$Id: ip_sockglue.c,v 1.35 1998/05/08 21:06:28 davem Exp $
+ * Version:	$Id: ip_sockglue.c,v 1.36 1998/07/15 05:05:06 davem Exp $
  *
  * Authors:	see ip.c
  *
@@ -70,17 +70,11 @@
 
 static void ip_cmsg_recv_ttl(struct msghdr *msg, struct sk_buff *skb)
 {
-	if (IPCB(skb)->opt.optlen == 0)
-		return;
-
 	put_cmsg(msg, SOL_IP, IP_TTL, 1, &skb->nh.iph->ttl);
 }
 
 static void ip_cmsg_recv_tos(struct msghdr *msg, struct sk_buff *skb)
 {
-	if (IPCB(skb)->opt.optlen == 0)
-		return;
-
 	put_cmsg(msg, SOL_IP, IP_TOS, 1, &skb->nh.iph->tos);
 }
 
diff -u --recursive --new-file v2.1.111/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
--- v2.1.111/linux/net/ipv4/ipconfig.c	Tue Jun 23 10:01:31 1998
+++ linux/net/ipv4/ipconfig.c	Sun Jul 26 23:35:57 1998
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.c,v 1.13 1998/06/09 03:40:47 zaitcev Exp $
+ *  $Id: ipconfig.c,v 1.15 1998/06/19 13:22:33 davem Exp $
  *
  *  Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
  *  information to configure own IP address and routes.
@@ -323,7 +323,7 @@
 	if (rarp->ar_op != htons(ARPOP_RREPLY))
 		goto drop;
 
-	/* If it's not ethernet, delete it. */
+	/* If it's not Ethernet, delete it. */
 	if (rarp->ar_pro != htons(ETH_P_IP))
 		goto drop;
 
diff -u --recursive --new-file v2.1.111/linux/net/ipv4/rarp.c linux/net/ipv4/rarp.c
--- v2.1.111/linux/net/ipv4/rarp.c	Tue Mar 17 22:18:16 1998
+++ linux/net/ipv4/rarp.c	Sun Jul 26 23:35:57 1998
@@ -3,11 +3,11 @@
  * Copyright (C) 1994 by Ross Martin
  * Based on linux/net/inet/arp.c, Copyright (C) 1994 by Florian La Roche
  *
- * $Id: rarp.c,v 1.24 1998/03/08 05:56:30 davem Exp $
+ * $Id: rarp.c,v 1.25 1998/06/19 13:22:34 davem Exp $
  *
  * This module implements the Reverse Address Resolution Protocol 
  * (RARP, RFC 903), which is used to convert low level addresses such
- * as ethernet addresses into high level addresses such as IP addresses.
+ * as Ethernet addresses into high level addresses such as IP addresses.
  * The most common use of RARP is as a means for a diskless workstation 
  * to discover its IP address during a network boot.
  *
@@ -19,7 +19,7 @@
  ***	unless you have all the rest to boot the box from it. 
  **
  * 
- * Currently, only ethernet address -> IP address is likely to work.
+ * Currently, only Ethernet address -> IP address is likely to work.
  * (Is RARP ever used for anything else?)
  *
  * This code is free software; you can redistribute it and/or
diff -u --recursive --new-file v2.1.111/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.1.111/linux/net/ipv4/route.c	Tue Jun 23 10:01:31 1998
+++ linux/net/ipv4/route.c	Sun Jul 26 23:35:57 1998
@@ -5,7 +5,7 @@
  *
  *		ROUTE - implementation of the IP router.
  *
- * Version:	$Id: route.c,v 1.52 1998/06/11 03:15:47 davem Exp $
+ * Version:	$Id: route.c,v 1.54 1998/07/15 05:05:22 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1166,7 +1166,7 @@
 	}
 
 	/* Multicast recognition logic is moved from route cache to here.
-	   The problem was that too many ethernet cards have broken/missing
+	   The problem was that too many Ethernet cards have broken/missing
 	   hardware multicast filters :-( As result the host on multicasting
 	   network acquires a lot of useless route cache entries, sort of
 	   SDR messages from all the world. Now we try to get rid of them.
@@ -1496,7 +1496,7 @@
 	nlh->nlmsg_flags = nowait ? NLM_F_MULTI : 0;
 	r->rtm_family = AF_INET;
 	r->rtm_dst_len = 32;
-	r->rtm_src_len = 32;
+	r->rtm_src_len = 0;
 	r->rtm_tos = rt->key.tos;
 	r->rtm_table = RT_TABLE_MAIN;
 	r->rtm_type = rt->rt_type;
@@ -1509,9 +1509,16 @@
 	o = skb->tail;
 #endif
 	RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst);
-	RTA_PUT(skb, RTA_SRC, 4, &rt->rt_src);
+	if (rt->key.src) {
+		r->rtm_src_len = 32;
+		RTA_PUT(skb, RTA_SRC, 4, &rt->key.src);
+	}
 	if (rt->u.dst.dev)
 		RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex);
+	if (rt->key.iif)
+		RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst);
+	else if (rt->rt_src != rt->key.src)
+		RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src);
 	if (rt->rt_dst != rt->rt_gateway)
 		RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway);
 #ifdef CONFIG_RTNL_OLD_IFINFO
@@ -1533,7 +1540,6 @@
 	if (mx->rta_len == RTA_LENGTH(0))
 		skb_trim(skb, (u8*)mx - skb->data);
 #endif
-	RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst);
 	ci.rta_lastuse = jiffies - rt->u.dst.lastuse;
 	ci.rta_used = atomic_read(&rt->u.dst.refcnt);
 	ci.rta_clntref = atomic_read(&rt->u.dst.use);
diff -u --recursive --new-file v2.1.111/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.1.111/linux/net/ipv4/tcp.c	Tue Jul 21 00:15:33 1998
+++ linux/net/ipv4/tcp.c	Sun Jul 26 23:35:57 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.115 1998/05/13 13:44:13 alan Exp $
+ * Version:	$Id: tcp.c,v 1.116 1998/07/26 03:06:54 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.111/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.1.111/linux/net/ipv4/tcp_input.c	Tue Jun 23 10:01:31 1998
+++ linux/net/ipv4/tcp_input.c	Sun Jul 26 23:35:57 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.119 1998/05/23 13:10:24 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.121 1998/07/15 04:39:12 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -156,8 +156,8 @@
 	}
 }
 
-/* Calculate rto without backoff. This is the second half of Van Jacobsons
- * routine refered to above.
+/* Calculate rto without backoff.  This is the second half of Van Jacobson's
+ * routine referred to above.
  */
 
 static __inline__ void tcp_set_rto(struct tcp_opt *tp)
@@ -186,13 +186,21 @@
 }
 
 /* WARNING: this must not be called if tp->saw_timestamp was false. */
-extern __inline__ void tcp_replace_ts_recent(struct tcp_opt *tp, __u32 end_seq)
+extern __inline__ void tcp_replace_ts_recent(struct sock *sk, struct tcp_opt *tp,
+					     __u32 start_seq, __u32 end_seq)
 {
 	/* From draft-ietf-tcplw-high-performance: the correct
 	 * test is last_ack_sent <= end_seq.
 	 * (RFC1323 stated last_ack_sent < end_seq.)
+	 *
+	 * HOWEVER: The current check contradicts the draft statements.
+	 * It has been done for good reasons.
+	 * The implemented check improves security and eliminates
+	 * unnecessary RTT overestimation.
+	 *		1998/06/27  Andrey V. Savochkin <saw@msu.ru>
 	 */
-	if (!before(end_seq, tp->last_ack_sent)) {
+	if (!before(end_seq, tp->last_ack_sent - sk->rcvbuf) &&
+	    !after(start_seq, tp->rcv_wup + tp->rcv_wnd)) {
 		/* PAWS bug workaround wrt. ACK frames, the PAWS discard
 		 * extra check below makes sure this can only happen
 		 * for pure ACK frames.  -DaveM
@@ -1657,7 +1665,9 @@
 					goto discard;
 				}
 			}
-			tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->end_seq);
+			tcp_replace_ts_recent(sk, tp,
+					      TCP_SKB_CB(skb)->seq,
+					      TCP_SKB_CB(skb)->end_seq);
 		}
 	}
 
@@ -2031,7 +2041,9 @@
 					goto discard;
 				}
 			}
-			tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->end_seq);
+			tcp_replace_ts_recent(sk, tp,
+					      TCP_SKB_CB(skb)->seq,
+					      TCP_SKB_CB(skb)->end_seq);
 		}
 	}
 
diff -u --recursive --new-file v2.1.111/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.1.111/linux/net/ipv4/tcp_ipv4.c	Thu May 14 19:47:45 1998
+++ linux/net/ipv4/tcp_ipv4.c	Sun Jul 26 23:35:57 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.147 1998/05/06 13:25:00 freitag Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.148 1998/07/23 12:28:25 freitag Exp $
  *
  *		IPv4 specific functions
  *
@@ -1033,7 +1033,14 @@
 	return dopt;
 }
 
-int sysctl_max_syn_backlog = 1024; 
+/* 
+ * Maximum number of SYN_RECV sockets in queue per LISTEN socket.
+ * One SYN_RECV socket costs about 80bytes on a 32bit machine.
+ * It would be better to replace it with a global counter for all sockets
+ * but then some measure against one socket starving all other sockets
+ * would be needed.
+ */
+int sysctl_max_syn_backlog = 128; 
 
 struct or_calltable or_ipv4 = {
 	tcp_v4_send_synack,
diff -u --recursive --new-file v2.1.111/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.1.111/linux/net/ipv4/tcp_output.c	Tue Jun 23 10:01:31 1998
+++ linux/net/ipv4/tcp_output.c	Sun Jul 26 23:35:57 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.91 1998/05/23 13:10:21 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.92 1998/06/19 13:22:44 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -166,10 +166,10 @@
 	}
 }
 
-/* Function to create two new tcp segments.  Shrinks the given segment
+/* Function to create two new TCP segments.  Shrinks the given segment
  * to the specified size and appends a new segment with the rest of the
- * packet to the list. This won't be called frenquently, I hope... 
- * Remember, these are still header-less SKB's at this point.
+ * packet to the list.  This won't be called frequently, I hope. 
+ * Remember, these are still headerless SKBs at this point.
  */
 static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len)
 {
@@ -256,7 +256,7 @@
 		 *
 		 * a) following SWS avoidance [and Nagle algorithm]
 		 * b) not exceeding our congestion window.
-		 * c) not retransmiting [Nagle]
+		 * c) not retransmitting [Nagle]
 		 */
 		while((skb = tp->send_head) && tcp_snd_test(sk, skb)) {
 			if (skb->len > mss_now) {
@@ -288,14 +288,14 @@
  * 2. We limit memory per socket
  *
  * RFC 1122:
- * "the suggested [SWS] avoidance algoritm for the receiver is to keep
+ * "the suggested [SWS] avoidance algorithm for the receiver is to keep
  *  RECV.NEXT + RCV.WIN fixed until:
  *  RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)"
  *
  * i.e. don't raise the right edge of the window until you can raise
  * it at least MSS bytes.
  *
- * Unfortunately, the recomended algorithm breaks header prediction,
+ * Unfortunately, the recommended algorithm breaks header prediction,
  * since header prediction assumes th->window stays fixed.
  *
  * Strictly speaking, keeping th->window fixed violates the receiver
@@ -474,7 +474,7 @@
 
 /* This retransmits one SKB.  Policy decisions and retransmit queue
  * state updates are done by the caller.  Returns non-zero if an
- * error occured which prevented the send.
+ * error occurred which prevented the send.
  */
 int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
 {
@@ -505,7 +505,7 @@
 	tp->retrans_out++;
 
 	/* Make a copy, if the first transmission SKB clone we made
-	 * is still in somebodies hands, else make a clone.
+	 * is still in somebody's hands, else make a clone.
 	 */
 	TCP_SKB_CB(skb)->when = jiffies;
 	if(skb_cloned(skb))
@@ -827,7 +827,7 @@
 		mss = min(mss, sk->user_mss);
 
 	if (mss < 1) {
-		printk(KERN_DEBUG "intial sk->mss below 1\n");
+		printk(KERN_DEBUG "initial sk->mss below 1\n");
 		mss = 1;	/* Sanity limit */
 	}
 
diff -u --recursive --new-file v2.1.111/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
--- v2.1.111/linux/net/ipv6/addrconf.c	Thu May 14 19:47:45 1998
+++ linux/net/ipv6/addrconf.c	Sun Jul 26 23:35:57 1998
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: addrconf.c,v 1.41 1998/05/08 21:06:31 davem Exp $
+ *	$Id: addrconf.c,v 1.43 1998/07/15 05:05:32 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -1034,7 +1034,7 @@
 	struct inet6_dev    * idev;
 
 	if (dev->type != ARPHRD_ETHER) {
-		/* Alas, we support only ethernet autoconfiguration. */
+		/* Alas, we support only Ethernet autoconfiguration. */
 		return;
 	}
 
@@ -1609,7 +1609,7 @@
 
 	{ inet6_rtm_newroute,	NULL,			},
 	{ inet6_rtm_delroute,	NULL,			},
-	{ NULL,			inet6_dump_fib,		},
+	{ inet6_rtm_getroute,	inet6_dump_fib,		},
 	{ NULL,			NULL,			},
 };
 #endif
diff -u --recursive --new-file v2.1.111/linux/net/ipv6/ip6_input.c linux/net/ipv6/ip6_input.c
--- v2.1.111/linux/net/ipv6/ip6_input.c	Thu May  7 22:51:56 1998
+++ linux/net/ipv6/ip6_input.c	Sun Jul 26 23:35:57 1998
@@ -6,7 +6,7 @@
  *	Pedro Roque		<roque@di.fc.ul.pt>
  *	Ian P. Morris		<I.P.Morris@soton.ac.uk>
  *
- *	$Id: ip6_input.c,v 1.9 1998/04/30 16:24:24 freitag Exp $
+ *	$Id: ip6_input.c,v 1.10 1998/07/15 05:05:34 davem Exp $
  *
  *	Based in linux/net/ipv4/ip_input.c
  *
@@ -65,11 +65,6 @@
 /* New header structures */
 
 
-struct ipv6_tlvtype {
-	u8 type;
-	u8 len;
-};
-
 struct tlvtype_proc {
 	u8	type;
 	int	(*func) (struct sk_buff *, struct device *dev, __u8 *ptr,
@@ -82,7 +77,7 @@
 	{255,			NULL}
 };
 
-static int ip6_dstopt_unknown(struct sk_buff *skb, struct ipv6_tlvtype *hdr)
+int ip6_dstopt_unknown(struct sk_buff *skb, struct ipv6_tlvtype *hdr)
 {
 	struct in6_addr *daddr;
 	int pos;
@@ -91,7 +86,7 @@
 	 *	unkown destination option type
 	 */
 	
-	pos = (__u8 *) skb->h.raw - (__u8 *) skb->nh.raw;
+	pos = (__u8 *) hdr - (__u8 *) skb->nh.raw;
 	
 	/* I think this is correct please check - IPM */
 
diff -u --recursive --new-file v2.1.111/linux/net/ipv6/ip6_output.c linux/net/ipv6/ip6_output.c
--- v2.1.111/linux/net/ipv6/ip6_output.c	Sat May  2 14:19:55 1998
+++ linux/net/ipv6/ip6_output.c	Sun Jul 26 23:35:57 1998
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: ip6_output.c,v 1.12 1998/04/11 22:11:06 davem Exp $
+ *	$Id: ip6_output.c,v 1.13 1998/07/15 05:05:38 davem Exp $
  *
  *	Based on linux/net/ipv4/ip_output.c
  *
@@ -32,6 +32,7 @@
 #include <net/protocol.h>
 #include <net/ip6_route.h>
 #include <net/addrconf.h>
+#include <net/rawv6.h>
 
 static u32	ipv6_fragmentation_id = 1;
 
@@ -519,25 +520,104 @@
 	return err;
 }
 
+int ip6_call_ra_chain(struct sk_buff *skb, int sel)
+{
+	struct ip6_ra_chain *ra;
+	struct sock *last = NULL;
+
+	for (ra = ip6_ra_chain; ra; ra = ra->next) {
+		struct sock *sk = ra->sk;
+		if (sk && ra->sel == sel) {
+			if (last) {
+				struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+				if (skb2) {
+					skb2->sk = last;
+					rawv6_rcv(skb2, skb2->dev, &skb2->nh.ipv6h->saddr,
+						  &skb2->nh.ipv6h->daddr, NULL, skb2->len);
+				}
+			}
+			last = sk;
+		}
+	}
+
+	if (last) {
+		skb->sk = last;
+		rawv6_rcv(skb, skb->dev, &skb->nh.ipv6h->saddr,
+			  &skb->nh.ipv6h->daddr, NULL, skb->len);
+		return 1;
+	}
+	return 0;
+}
+
 int ip6_forward(struct sk_buff *skb)
 {
 	struct dst_entry *dst = skb->dst;
 	struct ipv6hdr *hdr = skb->nh.ipv6h;
 	int size;
 	
-	if (ipv6_devconf.forwarding == 0) {
-		kfree_skb(skb);
-		return -EINVAL;
-	}
+	if (ipv6_devconf.forwarding == 0)
+		goto drop;
 
 	/*
 	 *	check hop-by-hop options present
 	 */
-#if 0
-	if (hdr->nexthdr == NEXTHDR_HOP)
-	{
+	/*
+	 *	Note, that NEXTHDR_HOP header must be checked
+	 *	always at the most beginning of ipv6_rcv.
+	 *	The result should be saved somewhere, but
+	 *	we do not it for now. Alas. Let's do it here. --ANK
+	 *
+	 *	Second note: we DO NOT make any processing on
+	 *	RA packets, pushing them to user level AS IS
+	 *	without ane WARRANTY that application will able
+	 *	to interpret them. The reson is that we
+	 *	cannot make anything clever here.
+	 *
+	 *	We are not end-node, so that if packet contains
+	 *	AH/ESP, we cannot make anything.
+	 *	Defragmentation also would be mistake, RA packets
+	 *	cannot be fragmented, because there is no warranty
+	 *	that different fragments will go along one path. --ANK
+	 */
+	if (hdr->nexthdr == NEXTHDR_HOP) {
+		int ra_value = -1;
+		u8 *ptr = (u8*)(skb->nh.ipv6h+1);
+		int len = (ptr[1]+1)<<3;
+
+		if (len + sizeof(struct ipv6hdr) > skb->len)
+			goto drop;
+
+		ptr += 2;
+		len -= 2;
+		while (len > 0) {
+			u8 *opt;
+			int optlen;
+
+			if (ptr[0] == 0) {
+				len--;
+				ptr++;
+				continue;
+			}
+			opt = ptr;
+			optlen = ptr[1]+1;
+
+			len -= optlen;
+			ptr += optlen;
+			if (len < 0)
+				goto drop;
+
+			if (opt[0] == 20) {
+				/* Router Alert as of draft-ietf-ipngwg-ipv6router-alert-04 */
+				if (optlen < 4)
+					goto drop;
+				ra_value = opt[2] + (opt[3]<<8);
+			} else if (!ip6_dstopt_unknown(skb, (struct ipv6_tlvtype*)opt))
+				goto drop;
+		}
+		if (ra_value>=0 && ip6_call_ra_chain(skb, ra_value))
+			return 0;
 	}
-#endif
+
 	/*
 	 *	check and decrement ttl
 	 */
@@ -589,4 +669,8 @@
 	dst->output(skb);
 
 	return 0;
+
+drop:
+	kfree_skb(skb);
+	return -EINVAL;
 }
diff -u --recursive --new-file v2.1.111/linux/net/ipv6/ipv6_sockglue.c linux/net/ipv6/ipv6_sockglue.c
--- v2.1.111/linux/net/ipv6/ipv6_sockglue.c	Thu May 14 19:47:45 1998
+++ linux/net/ipv6/ipv6_sockglue.c	Sun Jul 26 23:35:57 1998
@@ -7,7 +7,7 @@
  *
  *	Based on linux/net/ipv4/ip_sockglue.c
  *
- *	$Id: ipv6_sockglue.c,v 1.21 1998/05/07 15:43:13 davem Exp $
+ *	$Id: ipv6_sockglue.c,v 1.22 1998/07/15 05:05:39 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -67,6 +67,45 @@
 	0
 };
 
+struct ip6_ra_chain *ip6_ra_chain;
+
+int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
+{
+	struct ip6_ra_chain *ra, *new_ra, **rap;
+
+	/* RA packet may be delivered ONLY to IPPROTO_RAW socket */
+	if (sk->type != SOCK_RAW || sk->num != IPPROTO_RAW)
+		return -EINVAL;
+
+	new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
+
+	for (rap = &ip6_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {
+		if (ra->sk == sk) {
+			if (sel>=0) {
+				if (new_ra)
+					kfree(new_ra);
+				return -EADDRINUSE;
+			}
+			*rap = ra->next;
+			if (ra->destructor)
+				ra->destructor(sk);
+			kfree(ra);
+			return 0;
+		}
+	}
+	if (new_ra == NULL)
+		return -ENOBUFS;
+	new_ra->sk = sk;
+	new_ra->sel = sel;
+	new_ra->destructor = destructor;
+	start_bh_atomic();
+	new_ra->next = ra;
+	*rap = new_ra;
+	end_bh_atomic();
+	return 0;
+}
+
+
 int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval, 
 		    int optlen)
 {
@@ -74,6 +113,9 @@
 	int val, err;
 	int retv = -ENOPROTOOPT;
 
+	if(level==SOL_IP && sk->type != SOCK_RAW)
+		return udp_prot.setsockopt(sk, level, optname, optval, optlen);
+
 	if(level!=SOL_IPV6)
 		goto out;
 
@@ -197,7 +239,11 @@
 			retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
 		else
 			retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
+		break;
 	}
+	case IPV6_ROUTER_ALERT:
+		retv = ip6_ra_control(sk, val, NULL);
+		break;
 	};
 
 out:
@@ -207,7 +253,11 @@
 int ipv6_getsockopt(struct sock *sk, int level, int optname, char *optval, 
 		    int *optlen)
 {
-	return 0;
+	if(level==SOL_IP && sk->type != SOCK_RAW)
+		return udp_prot.getsockopt(sk, level, optname, optval, optlen);
+	if(level!=SOL_IPV6)
+		return -ENOPROTOOPT;
+	return -EINVAL;
 }
 
 #if defined(MODULE) && defined(CONFIG_SYSCTL)
diff -u --recursive --new-file v2.1.111/linux/net/ipv6/raw.c linux/net/ipv6/raw.c
--- v2.1.111/linux/net/ipv6/raw.c	Thu Mar 26 15:57:13 1998
+++ linux/net/ipv6/raw.c	Sun Jul 26 23:35:58 1998
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/raw.c
  *
- *	$Id: raw.c,v 1.19 1998/03/20 09:12:20 davem Exp $
+ *	$Id: raw.c,v 1.20 1998/07/15 05:05:41 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -596,6 +596,8 @@
 {
 	sk->state = TCP_CLOSE;
 	ipv6_sock_mc_close(sk);
+	if (sk->num == IPPROTO_RAW)
+		ip6_ra_control(sk, -1, NULL);
 	sk->dead = 1;
 	destroy_sock(sk);
 }
diff -u --recursive --new-file v2.1.111/linux/net/ipv6/route.c linux/net/ipv6/route.c
--- v2.1.111/linux/net/ipv6/route.c	Thu May 14 19:47:45 1998
+++ linux/net/ipv6/route.c	Sun Jul 26 23:35:58 1998
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: route.c,v 1.30 1998/05/08 21:06:33 davem Exp $
+ *	$Id: route.c,v 1.32 1998/07/25 23:28:52 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -1722,7 +1722,6 @@
 	return err;
 }
 
-
 struct rt6_rtnl_dump_arg
 {
 	struct sk_buff *skb;
@@ -1733,6 +1732,9 @@
 };
 
 static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
+			 struct in6_addr *dst,
+			 struct in6_addr *src,
+			 int iif,
 			 int type, pid_t pid, u32 seq)
 {
 	struct rtmsg *rtm;
@@ -1777,10 +1779,23 @@
 #ifdef CONFIG_RTNL_OLD_IFINFO
 	o = skb->tail;
 #endif
-	if (rtm->rtm_dst_len)
+	if (dst) {
+		RTA_PUT(skb, RTA_DST, 16, dst);
+	        rtm->rtm_dst_len = 128;
+	} else if (rtm->rtm_dst_len)
 		RTA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr);
-	if (rtm->rtm_src_len)
+	if (src) {
+		RTA_PUT(skb, RTA_SRC, 16, src);
+	        rtm->rtm_src_len = 128;
+	} else if (rtm->rtm_src_len)
 		RTA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr);
+	if (iif)
+		RTA_PUT(skb, RTA_IIF, 4, &iif);
+	else if (dst) {
+		struct inet6_ifaddr *ifp = ipv6_get_saddr(&rt->u.dst, dst);
+		if (ifp)
+			RTA_PUT(skb, RTA_PREFSRC, 16, &ifp->addr);
+	}
 #ifdef CONFIG_RTNL_OLD_IFINFO
 	if (rt->u.dst.pmtu)
 		RTA_PUT(skb, RTA_MTU, sizeof(unsigned), &rt->u.dst.pmtu);
@@ -1842,7 +1857,7 @@
 			arg->count++;
 			continue;
 		}
-		if (rt6_fill_node(arg->skb, rt, RTM_NEWROUTE,
+		if (rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
 				  NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq) <= 0) {
 			arg->stop = 1;
 			break;
@@ -1870,6 +1885,68 @@
 	return skb->len;
 }
 
+int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
+{
+	struct rtattr **rta = arg;
+	int iif = 0;
+	int err;
+	struct sk_buff *skb;
+	struct flowi fl;
+	struct rt6_info *rt;
+
+	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (skb == NULL)
+		return -ENOBUFS;
+
+	/* Reserve room for dummy headers, this skb can pass
+	   through good chunk of routing engine.
+	 */
+	skb->mac.raw = skb->data;
+	skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
+
+	fl.proto = 0;
+	fl.nl_u.ip6_u.daddr = NULL;
+	fl.nl_u.ip6_u.saddr = NULL;
+	fl.uli_u.icmpt.type = 0;
+	fl.uli_u.icmpt.code = 0;
+	if (rta[RTA_SRC-1])
+		fl.nl_u.ip6_u.saddr = (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1]);
+	if (rta[RTA_DST-1])
+		fl.nl_u.ip6_u.daddr = (struct in6_addr*)RTA_DATA(rta[RTA_DST-1]);
+
+	if (rta[RTA_IIF-1])
+		memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int));
+
+	if (iif) {
+		struct device *dev;
+		dev = dev_get_by_index(iif);
+		if (!dev)
+			return -ENODEV;
+	}
+
+	fl.oif = 0;
+	if (rta[RTA_OIF-1])
+		memcpy(&fl.oif, RTA_DATA(rta[RTA_OIF-1]), sizeof(int));
+
+	rt = (struct rt6_info*)ip6_route_output(NULL, &fl);
+
+	skb->dst = &rt->u.dst;
+
+	NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
+	err = rt6_fill_node(skb, rt, 
+			    fl.nl_u.ip6_u.daddr,
+			    fl.nl_u.ip6_u.saddr,
+			    iif,
+			    RTM_NEWROUTE, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq);
+	if (err < 0)
+		return -EMSGSIZE;
+
+	err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
 void inet6_rt_notify(int event, struct rt6_info *rt)
 {
 	struct sk_buff *skb;
@@ -1880,7 +1957,7 @@
 		netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, ENOBUFS);
 		return;
 	}
-	if (rt6_fill_node(skb, rt, event, 0, 0) < 0) {
+	if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0) < 0) {
 		kfree_skb(skb);
 		netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL);
 		return;
diff -u --recursive --new-file v2.1.111/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
--- v2.1.111/linux/net/ipv6/udp.c	Tue Jun 23 10:01:31 1998
+++ linux/net/ipv6/udp.c	Sun Jul 26 23:35:58 1998
@@ -7,7 +7,7 @@
  *
  *	Based on linux/ipv4/udp.c
  *
- *	$Id: udp.c,v 1.29 1998/05/15 15:21:39 davem Exp $
+ *	$Id: udp.c,v 1.31 1998/07/15 05:05:45 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -185,12 +185,18 @@
 int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
 	struct sockaddr_in6	*usin = (struct sockaddr_in6 *) uaddr;
+	struct ipv6_pinfo      	*np = &sk->net_pinfo.af_inet6;
 	struct in6_addr		*daddr;
 	struct dst_entry	*dst;
-	struct ipv6_pinfo      	*np;
 	struct inet6_ifaddr	*ifa;
 	struct flowi		fl;
 	int			addr_type;
+	int			err;
+
+	if (usin->sin6_family == AF_INET) {
+		err = udp_connect(sk, uaddr, addr_len);
+		goto ipv4_connected;
+	}
 
 	if (addr_len < sizeof(*usin)) 
 	  	return(-EINVAL);
@@ -199,7 +205,6 @@
 	  	return(-EAFNOSUPPORT);
 
 	addr_type = ipv6_addr_type(&usin->sin6_addr);
-	np = &sk->net_pinfo.af_inet6;
 
 	if (addr_type == IPV6_ADDR_ANY) {
 		/*
@@ -212,18 +217,21 @@
 
 	if (addr_type == IPV6_ADDR_MAPPED) {
 		struct sockaddr_in sin;
-		int err;
 
 		sin.sin_family = AF_INET;
 		sin.sin_addr.s_addr = daddr->s6_addr32[3];
+		sin.sin_port = usin->sin6_port;
 
 		err = udp_connect(sk, (struct sockaddr*) &sin, sizeof(sin));
-		
+
+ipv4_connected:
 		if (err < 0)
 			return err;
 		
-		ipv6_addr_copy(&np->daddr, daddr);
-		
+		ipv6_addr_set(&np->daddr, 0, 0, 
+			      __constant_htonl(0x0000ffff),
+			      sk->daddr);
+
 		if(ipv6_addr_any(&np->saddr)) {
 			ipv6_addr_set(&np->saddr, 0, 0, 
 				      __constant_htonl(0x0000ffff),
@@ -236,7 +244,7 @@
 				      __constant_htonl(0x0000ffff),
 				      sk->rcv_saddr);
 		}
-
+		return 0;
 	}
 
 	ipv6_addr_copy(&np->daddr, daddr);
@@ -347,6 +355,8 @@
 		if (skb->protocol == __constant_htons(ETH_P_IP)) {
 			ipv6_addr_set(&sin6->sin6_addr, 0, 0,
 				      __constant_htonl(0xffff), skb->nh.iph->saddr);
+			if (sk->ip_cmsg_flags)
+				ip_cmsg_recv(msg, skb);
 		} else {
 			memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr,
 			       sizeof(struct in6_addr));
@@ -668,6 +678,9 @@
 		return(-EINVAL);
 
 	if (sin6) {
+		if (sin6->sin6_family == AF_INET)
+			return udp_sendmsg(sk, msg, ulen);
+
 		if (addr_len < sizeof(*sin6))
 			return(-EINVAL);
 		
@@ -702,8 +715,10 @@
 		
 		sin.sin_family = AF_INET;
 		sin.sin_addr.s_addr = daddr->s6_addr32[3];
+		sin.sin_port = udh.uh.dest;
+		msg->msg_name = (struct sockaddr *)(&sin);
 
-		return udp_sendmsg(sk, msg, len);
+		return udp_sendmsg(sk, msg, ulen);
 	}
 
 	udh.daddr = NULL;
diff -u --recursive --new-file v2.1.111/linux/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c
--- v2.1.111/linux/net/netlink/af_netlink.c	Thu May 14 19:47:45 1998
+++ linux/net/netlink/af_netlink.c	Sun Jul 26 23:35:58 1998
@@ -986,15 +986,15 @@
 	netlink_release,
 	netlink_bind,
 	netlink_connect,
-	NULL,
-	NULL,
+	sock_no_socketpair,
+	sock_no_accept,
 	netlink_getname,
 	datagram_poll,
 	sock_no_ioctl,
 	sock_no_listen,
 	sock_no_shutdown,
-	NULL,
-	NULL,
+	sock_no_setsockopt,
+	sock_no_getsockopt,
 	sock_no_fcntl,
 	netlink_sendmsg,
 	netlink_recvmsg
diff -u --recursive --new-file v2.1.111/linux/net/netsyms.c linux/net/netsyms.c
--- v2.1.111/linux/net/netsyms.c	Thu Jul 16 18:09:32 1998
+++ linux/net/netsyms.c	Sun Jul 26 23:35:58 1998
@@ -60,8 +60,7 @@
 	defined(CONFIG_EL2)	||	defined(CONFIG_NE2000)		|| \
 	defined(CONFIG_E2100)	||	defined(CONFIG_HPLAN_PLUS)	|| \
 	defined(CONFIG_HPLAN)	||	defined(CONFIG_AC3200)		|| \
-	defined(CONFIG_ES3210)	||	defined(CONFIG_ULTRA32)		|| \
-	defined(CONFIG_LNE390)
+	defined(CONFIG_ES3210)
 #include "../drivers/net/8390.h"
 #endif
 
@@ -85,8 +84,8 @@
 EXPORT_SYMBOL(dev_lockct);
 
 /* Skbuff symbols. */
-EXPORT_SYMBOL(skb_push_errstr);
-EXPORT_SYMBOL(skb_put_errstr);
+EXPORT_SYMBOL(skb_over_panic);
+EXPORT_SYMBOL(skb_under_panic);
 
 /* Socket layer registration */
 EXPORT_SYMBOL(sock_register);
@@ -222,6 +221,7 @@
 EXPORT_SYMBOL(ip_mc_dec_group);
 EXPORT_SYMBOL(__ip_finish_output);
 EXPORT_SYMBOL(inet_dgram_ops);
+EXPORT_SYMBOL(ip_cmsg_recv);
 EXPORT_SYMBOL(__release_sock);
 
 /* needed for ip_gre -cw */
@@ -358,8 +358,7 @@
 	defined(CONFIG_EL2)	||	defined(CONFIG_NE2000)		|| \
 	defined(CONFIG_E2100)	||	defined(CONFIG_HPLAN_PLUS)	|| \
 	defined(CONFIG_HPLAN)	||	defined(CONFIG_AC3200)		|| \
-	defined(CONFIG_ES3210)	||	defined(CONFIG_ULTRA32)		|| \
-	defined(CONFIG_LNE390)
+	defined(CONFIG_ES3210)
 /* If 8390 NIC support is built in, we will need these. */
 EXPORT_SYMBOL(ei_open);
 EXPORT_SYMBOL(ei_close);
diff -u --recursive --new-file v2.1.111/linux/net/packet/af_packet.c linux/net/packet/af_packet.c
--- v2.1.111/linux/net/packet/af_packet.c	Fri May  8 23:14:57 1998
+++ linux/net/packet/af_packet.c	Sun Jul 26 23:35:58 1998
@@ -1182,8 +1182,8 @@
 	packet_release,
 	packet_bind_spkt,
 	sock_no_connect,
-	NULL,
-	NULL,
+	sock_no_socketpair,
+	sock_no_accept,
 	packet_getname_spkt,
 	datagram_poll,
 	packet_ioctl,
diff -u --recursive --new-file v2.1.111/linux/net/x25/af_x25.c linux/net/x25/af_x25.c
--- v2.1.111/linux/net/x25/af_x25.c	Thu May  7 22:51:56 1998
+++ linux/net/x25/af_x25.c	Sun Jul 26 23:35:58 1998
@@ -174,7 +174,8 @@
 	struct sock *s;
 
 	for (s = x25_list; s != NULL; s = s->next)
-		if (s->protinfo.x25->neighbour->dev == dev)
+		if (s->protinfo.x25->neighbour &&
+		    s->protinfo.x25->neighbour->dev == dev)
 			x25_disconnect(s, ENETUNREACH, 0, 0);
 }
 
@@ -621,6 +622,9 @@
 	if ((sk->protinfo.x25->neighbour = x25_get_neigh(dev)) == NULL)
 		return -ENETUNREACH;
 
+	x25_limit_facilities(&sk->protinfo.x25->facilities,
+			     sk->protinfo.x25->neighbour);
+
 	if ((sk->protinfo.x25->lci = x25_new_lci(sk->protinfo.x25->neighbour)) == 0)
 		return -ENETUNREACH;
 
@@ -787,6 +791,13 @@
 	}
 
 	/*
+	 * current neighbour/link might impose additional limits
+	 * on certain facilties
+	 */
+
+	x25_limit_facilities(&facilities,neigh);
+
+	/*
 	 *	Try to create a new socket.
 	 */
 	if ((make = x25_make_new(sk)) == NULL) {
@@ -1124,18 +1135,8 @@
 				return -EINVAL;
 			if (facilities.pacsize_out < X25_PS16 || facilities.pacsize_out > X25_PS4096)
 				return -EINVAL;
-			if (sk->state == TCP_CLOSE || sk->protinfo.x25->neighbour->extended) 
-			{
-				if (facilities.winsize_in < 1 || facilities.winsize_in > 127)
-					return -EINVAL;
-				if (facilities.winsize_out < 1 || facilities.winsize_out > 127)
-					return -EINVAL;
-			} else {
-				if (facilities.winsize_in < 1 || facilities.winsize_in > 7)
-					return -EINVAL;
-				if (facilities.winsize_out < 1 || facilities.winsize_out > 7)
-					return -EINVAL;
-			}
+			if (facilities.winsize_in < 1 || facilities.winsize_in > 127)
+				return -EINVAL;
 			if (facilities.throughput < 0x03 || facilities.throughput > 0x2C)
 				return -EINVAL;
 			if (facilities.reverse != 0 && facilities.reverse != 1)
@@ -1275,6 +1276,16 @@
 	x25_device_event,
 	0
 };
+
+void x25_kill_by_neigh(struct x25_neigh *neigh)
+{
+	struct sock *s;
+
+	for( s=x25_list; s != NULL; s=s->next){
+		if( s->protinfo.x25->neighbour == neigh )
+			x25_disconnect(s, ENETUNREACH, 0, 0);
+	} 
+}
 
 #ifdef CONFIG_PROC_FS
 static struct proc_dir_entry proc_net_x25 = {
diff -u --recursive --new-file v2.1.111/linux/net/x25/x25_dev.c linux/net/x25/x25_dev.c
--- v2.1.111/linux/net/x25/x25_dev.c	Thu Feb 12 20:56:15 1998
+++ linux/net/x25/x25_dev.c	Sun Jul 26 23:35:58 1998
@@ -98,6 +98,7 @@
 int x25_lapb_receive_frame(struct sk_buff *skb, struct device *dev, struct packet_type *ptype)
 {
 	struct x25_neigh *neigh;
+	int queued;
 
 	skb->sk = NULL;
 
@@ -113,7 +114,13 @@
 	switch (skb->data[0]) {
 		case 0x00:
 			skb_pull(skb, 1);
-			return x25_receive_data(skb, neigh);
+			queued = x25_receive_data(skb, neigh);
+			if( ! queued )
+				/* We need to free the skb ourselves because
+				 * net_bh() won't care about our return code.
+				 */
+				kfree_skb(skb);
+			return 0;
 
 		case 0x01:
 			x25_link_established(neigh);
@@ -215,6 +222,8 @@
 {
 	unsigned char *dptr;
 
+	skb->nh.raw = skb->data;
+
 	switch (neigh->dev->type) {
 		case ARPHRD_X25:
 			dptr  = skb_push(skb, 1);
@@ -238,3 +247,6 @@
 }
 
 #endif
+
+
+
diff -u --recursive --new-file v2.1.111/linux/net/x25/x25_facilities.c linux/net/x25/x25_facilities.c
--- v2.1.111/linux/net/x25/x25_facilities.c	Mon Jul  7 08:20:00 1997
+++ linux/net/x25/x25_facilities.c	Sun Jul 26 23:35:58 1998
@@ -200,4 +200,26 @@
 	return len;
 }
 
+/*
+ *	Limit values of certain facilities according to the capability of the 
+ *      currently attached x25 link.
+ */
+void x25_limit_facilities(struct x25_facilities *facilities,
+			  struct x25_neigh *neighbour)
+{
+
+	if( ! neighbour->extended ){
+		if( facilities->winsize_in  > 7 ){
+			printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n");
+			facilities->winsize_in = 7;
+		}
+		if( facilities->winsize_out > 7 ){
+			facilities->winsize_out = 7;
+			printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n");
+		}
+	}
+}
+
 #endif
+
+
diff -u --recursive --new-file v2.1.111/linux/net/x25/x25_in.c linux/net/x25/x25_in.c
--- v2.1.111/linux/net/x25/x25_in.c	Tue Apr 14 14:29:27 1998
+++ linux/net/x25/x25_in.c	Sun Jul 26 23:35:58 1998
@@ -49,17 +49,20 @@
 	if (more) {
 		sk->protinfo.x25->fraglen += skb->len;
 		skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb);
+		skb_set_owner_r(skb, sk);
 		return 0;
 	}
 
 	if (!more && sk->protinfo.x25->fraglen > 0) {	/* End of fragment */
-		sk->protinfo.x25->fraglen += skb->len;
-		skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb);
+		int len = sk->protinfo.x25->fraglen + skb->len;
 
-		if ((skbn = alloc_skb(sk->protinfo.x25->fraglen, GFP_ATOMIC)) == NULL)
+		if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){
+			kfree_skb(skb);
 			return 1;
+		}
+
+		skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb);
 
-		skb_set_owner_r(skbn, sk);
 		skbn->h.raw = skbn->data;
 
 		skbo = skb_dequeue(&sk->protinfo.x25->fragment_queue);
@@ -75,7 +78,12 @@
 		sk->protinfo.x25->fraglen = 0;		
 	}
 
-	return sock_queue_rcv_skb(sk, skbn);
+	skb_set_owner_r(skbn, sk);
+	skb_queue_tail(&sk->receive_queue, skbn);
+	if (!sk->dead)
+		sk->data_ready(sk,skbn->len);
+
+	return 0;
 }
 
 /*
diff -u --recursive --new-file v2.1.111/linux/net/x25/x25_link.c linux/net/x25/x25_link.c
--- v2.1.111/linux/net/x25/x25_link.c	Thu Feb 12 20:56:15 1998
+++ linux/net/x25/x25_link.c	Sun Jul 26 23:35:58 1998
@@ -264,11 +264,14 @@
 
 /*
  *	Called when the link layer has terminated, or an establishment
- *	request has failed. XXX should tell sockets.
+ *	request has failed.
  */
+
 void x25_link_terminated(struct x25_neigh *neigh)
 {
 	neigh->state = X25_LINK_STATE_0;
+	/* Out of order: clear existing virtual calls (X.25 03/93 4.6.3) */
+	x25_kill_by_neigh(neigh);
 }
 
 /*
