diff -u --recursive --new-file v2.2.8/linux/Makefile linux/Makefile
--- v2.2.8/linux/Makefile	Tue May 11 13:10:27 1999
+++ linux/Makefile	Wed May 12 08:50:12 1999
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 2
-SUBLEVEL = 8
+SUBLEVEL = 9
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
diff -u --recursive --new-file v2.2.8/linux/arch/m68k/kernel/ints.c linux/arch/m68k/kernel/ints.c
--- v2.2.8/linux/arch/m68k/kernel/ints.c	Tue May 11 13:10:27 1999
+++ linux/arch/m68k/kernel/ints.c	Wed May 12 08:50:08 1999
@@ -25,6 +25,7 @@
  *           which must be served                               /Roman Zippel
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/kernel_stat.h>
diff -u --recursive --new-file v2.2.8/linux/arch/m68k/mm/kmap.c linux/arch/m68k/mm/kmap.c
--- v2.2.8/linux/arch/m68k/mm/kmap.c	Tue May 11 13:10:27 1999
+++ linux/arch/m68k/mm/kmap.c	Wed May 12 08:50:08 1999
@@ -7,6 +7,7 @@
  *	     used by other architectures		/Roman Zippel
  */
 
+#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.2.8/linux/arch/m68k/mvme147/config.c linux/arch/m68k/mvme147/config.c
--- v2.2.8/linux/arch/m68k/mvme147/config.c	Tue May 11 13:10:27 1999
+++ linux/arch/m68k/mvme147/config.c	Wed May 12 08:50:08 1999
@@ -13,7 +13,6 @@
  * for more details.
  */
 
-#include <linux/config.h>
 #include <stdarg.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.2.8/linux/arch/m68k/q40/config.c linux/arch/m68k/q40/config.c
--- v2.2.8/linux/arch/m68k/q40/config.c	Tue May 11 13:10:27 1999
+++ linux/arch/m68k/q40/config.c	Wed May 12 08:50:08 1999
@@ -13,6 +13,7 @@
  */
 
 #include <stdarg.h>
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.2.8/linux/arch/m68k/sun3x/time.c linux/arch/m68k/sun3x/time.c
--- v2.2.8/linux/arch/m68k/sun3x/time.c	Tue May 11 13:10:27 1999
+++ linux/arch/m68k/sun3x/time.c	Wed May 12 08:50:08 1999
@@ -4,7 +4,6 @@
  *  Sun3x-specific time handling
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.2.8/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c
--- v2.2.8/linux/arch/ppc/kernel/pmac_pic.c	Tue May 11 13:10:28 1999
+++ linux/arch/ppc/kernel/pmac_pic.c	Wed May 12 08:50:08 1999
@@ -1,4 +1,4 @@
-
+#include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.2.8/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c
--- v2.2.8/linux/drivers/block/ide-dma.c	Tue Jan 19 11:32:51 1999
+++ linux/drivers/block/ide-dma.c	Tue May 11 14:58:46 1999
@@ -425,7 +425,7 @@
 	} else {
 		dma_base = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
 		if (!dma_base || dma_base == PCI_BASE_ADDRESS_IO_MASK) {
-			printk("%s: dma_base is invalid (0x%04lx, BIOS problem), please report to <mj@ucw.cz>\n", name, dma_base);
+			printk("%s: dma_base is invalid (0x%04lx)\n", name, dma_base);
 			dma_base = 0;
 		}
 	}
diff -u --recursive --new-file v2.2.8/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.2.8/linux/drivers/block/ide.c	Tue May 11 13:10:28 1999
+++ linux/drivers/block/ide.c	Wed May 12 13:19:32 1999
@@ -1696,6 +1696,7 @@
 	ide_hwgroup_t *hwgroup;
 	int irq_count = 0, unit, i;
 	unsigned long flags;
+	unsigned int p, minor;
 
 	if (index >= MAX_HWIFS)
 		return;
@@ -1714,6 +1715,24 @@
 			goto abort;
 	}
 	hwif->present = 0;
+	
+	/*
+	 * All clear?  Then blow away the buffer cache
+	 */
+	sti();
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		drive = &hwif->drives[unit];
+		minor = drive->select.b.unit << PARTN_BITS;
+		for (p = 0; p < (1<<PARTN_BITS); ++p) {
+			if (drive->part[p].nr_sects > 0) {
+				kdev_t devp = MKDEV(hwif->major, minor+p);
+				struct super_block * sb = get_super(devp);
+				if (sb) invalidate_inodes(sb);
+				invalidate_buffers (devp);
+			}
+		}
+	}
+	cli();
 	hwgroup = hwif->hwgroup;
 
 	/*
diff -u --recursive --new-file v2.2.8/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v2.2.8/linux/drivers/scsi/aha152x.c	Fri Apr 16 14:47:30 1999
+++ linux/drivers/scsi/aha152x.c	Wed May 12 13:19:32 1999
@@ -414,8 +414,13 @@
 #define P_PARITY   2
 
 /* possible irq range */
+#ifdef PCMCIA
+#define IRQ_MIN 0
+#define IRQ_MAX 16
+#else
 #define IRQ_MIN 9
 #define IRQ_MAX 12
+#endif
 #define IRQS    IRQ_MAX-IRQ_MIN+1
 
 enum {
@@ -746,7 +751,7 @@
   if(!aha152x_porttest(setup->io_port))
     return 0;
   
-  if(setup->irq<IRQ_MIN && setup->irq>IRQ_MAX)
+  if((setup->irq<IRQ_MIN) || (setup->irq>IRQ_MAX))
     return 0;
   
   if((setup->scsiid < 0) || (setup->scsiid > 7))
diff -u --recursive --new-file v2.2.8/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- v2.2.8/linux/drivers/video/Config.in	Tue Mar 23 14:35:48 1999
+++ linux/drivers/video/Config.in	Tue May 11 16:30:36 1999
@@ -21,6 +21,9 @@
   if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
     bool 'Acorn VIDC support' CONFIG_FB_ACORN
   fi
+  if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then
+    tristate 'Cyber2000 support' CONFIG_FB_CYBER2000
+  fi
   if [ "$CONFIG_APOLLO" = "y" ]; then
     define_bool CONFIG_FB_APOLLO y
   fi
@@ -177,8 +180,8 @@
 	 "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
 	 "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
          "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
-         "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
-         "$CONFIG_FB_SGIVW" = "y" ]; then
+	 "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
+	 "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" ]; then
       define_bool CONFIG_FBCON_CFB8 y
     else
       if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
@@ -191,8 +194,8 @@
 	   "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
 	   "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
            "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
-           "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
-           "$CONFIG_FB_SGIVW" = "m" ]; then
+	   "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
+	   "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" ]; then
 	define_bool CONFIG_FBCON_CFB8 m
       fi
     fi
@@ -204,7 +207,8 @@
 	 "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
 	 "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
 	 "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
-	 "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" ]; then
+	 "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
+	 "$CONFIG_FB_CYBER2000" = "y" ]; then
       define_bool CONFIG_FBCON_CFB16 y
     else
       if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
@@ -214,19 +218,22 @@
 	   "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
 	   "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
  	   "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
- 	   "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
-	   "$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" ]; then
+	   "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
+	   "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "m" -o \
+	   "$CONFIG_FB_CYBER2000" = "m" ]; then
 	define_bool CONFIG_FBCON_CFB16 m
       fi
     fi
     if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
 	 "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
-	  "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" ]; then
+	  "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
+	 "$CONFIG_FB_CYBER2000" = "y" ]; then
       define_bool CONFIG_FBCON_CFB24 y
     else
       if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
 	   "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
-	   "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" ]; then
+	   "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
+	   "$CONFIG_FB_CYBER2000" = "m" ]; then
 	define_bool CONFIG_FBCON_CFB24 m
       fi
     fi
@@ -323,7 +330,7 @@
       if [ "$CONFIG_AMIGA" = "y" ]; then
         define_bool CONFIG_FONT_PEARL_8x8 y
       fi
-      if [ "$CONFIG_ARM" = "y" ]; then
+      if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_ACORN" = "y" ]; then
         define_bool CONFIG_FONT_ACORN_8x8 y
       fi
     fi
diff -u --recursive --new-file v2.2.8/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.2.8/linux/drivers/video/Makefile	Tue Mar 23 14:35:48 1999
+++ linux/drivers/video/Makefile	Tue May 11 16:30:36 1999
@@ -132,6 +132,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_FB_CYBER2000),y)
+L_OBJS += cyber2000fb.o
+else
+  ifeq ($(CONFIG_FB_CYBER2000),m)
+  M_OBJS += cyber2000fb.o
+  endif
+endif
+
 ifeq ($(CONFIG_FB_SGIVW),y)
 L_OBJS += sgivwfb.o
 else
diff -u --recursive --new-file v2.2.8/linux/drivers/video/acornfb.c linux/drivers/video/acornfb.c
--- v2.2.8/linux/drivers/video/acornfb.c	Mon Oct  5 13:13:41 1998
+++ linux/drivers/video/acornfb.c	Tue May 11 16:30:36 1999
@@ -1,15 +1,22 @@
 /*
  * linux/drivers/video/acorn.c
  *
- * Copyright (C) 1998 Russell King
+ * Copyright (C) 1998,1999 Russell King
  *
  * Frame buffer code for Acorn platforms
+ *
+ * NOTE: Most of the modes with X!=640 will disappear shortly.
+ * NOTE: Startup setting of HS & VS polarity not supported.
+ *       (do we need to support it if we're coming up in 640x480?)
  */
+
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/string.h>
+#include <linux/ctype.h>
 #include <linux/mm.h>
 #include <linux/tty.h>
 #include <linux/malloc.h>
@@ -21,245 +28,898 @@
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
+#include <video/fbcon.h>
 #include <video/fbcon-mfb.h>
 #include <video/fbcon-cfb2.h>
 #include <video/fbcon-cfb4.h>
 #include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+
+/*
+ * Default resolution.
+ * NOTE that it has to be supported in the table towards
+ * the end of this file.
+ */
+#define DEFAULT_XRES	640
+#define DEFAULT_YRES	480
+
+/*
+ * define this to debug the video mode selection
+ */
+#undef DEBUG_MODE_SELECTION
+
+#if defined(HAS_VIDC20)
+#define VIDC_PALETTE_SIZE	256
+#define VIDC_NAME		"VIDC20"
+#elif defined(HAS_VIDC)
+#include <asm/memc.h>
+#define VIDC_PALETTE_SIZE	16
+#define VIDC_NAME		"VIDC"
+#endif
 
-#define MAX_VIDC20_PALETTE	256
-#define MAX_VIDC_PALETTE	16
+#define EXTEND8(x) ((x)|(x)<<8)
+#define EXTEND4(x) ((x)|(x)<<4|(x)<<8|(x)<<16)
+
+struct vidc20_palette {
+	u_int red:8;
+	u_int green:8;
+	u_int blue:8;
+	u_int ext:4;
+	u_int unused:4;
+};
+
+struct vidc_palette {
+	u_int red:4;
+	u_int green:4;
+	u_int blue:4;
+	u_int trans:1;
+	u_int sbz1:13;
+	u_int reg:4;
+	u_int sbz2:2;
+};
+
+union palette {
+	struct vidc20_palette	vidc20;
+	struct vidc_palette	vidc;
+	u_int	p;
+};
 
 struct acornfb_par {
-	unsigned long screen_base;
-	unsigned int xres;
-	unsigned int yres;
-	unsigned char bits_per_pixel;
-	unsigned int palette_size;
+	unsigned long	screen_base;
+	unsigned long	screen_base_p;
+	unsigned long	screen_end;
+	unsigned long	screen_size;
+	unsigned int	dram_size;
+	unsigned int	vram_half_sam;
+	unsigned int	palette_size;
+	  signed int	montype;
+	  signed int	currcon;
+	unsigned int	allow_modeset	: 1;
+	unsigned int	using_vram	: 1;
+	unsigned int	dpms		: 1;
+
+	union palette palette[VIDC_PALETTE_SIZE];
 
 	union {
-		union {
-			struct {
-				unsigned long red:8;
-				unsigned long green:8;
-				unsigned long blue:8;
-				unsigned long ext:4;
-				unsigned long unused:4;
-			} d;
-			unsigned long p;
-		} vidc20[MAX_VIDC20_PALETTE];
-		union {
-			struct {
-				unsigned long red:4;
-				unsigned long green:4;
-				unsigned long blue:4;
-				unsigned long trans:1;
-				unsigned long unused:19;
-			} d;
-			unsigned long p;
-		} vidc[MAX_VIDC_PALETTE];
-	} palette;
+		unsigned short cfb16[16];
+		unsigned long  cfb32[16];
+	} cmap;
 };
 
-static int currcon = 0;
-static struct display disp;
+/*
+ * Translation from RISC OS monitor types to actual
+ * HSYNC and VSYNC frequency ranges.  These are
+ * probably not right...
+ */
+#define NR_MONTYPES	6
+static struct fb_monspecs monspecs[NR_MONTYPES] __initdata = {
+	{ 15625, 15625, 50, 50, 0 },	/* TV		*/
+	{     0, 99999,  0, 99, 0 },	/* Multi Freq	*/
+	{ 58608, 58608, 64, 64, 0 },	/* Hi-res mono	*/
+	{ 30000, 70000, 60, 60, 0 },	/* VGA		*/
+	{ 30000, 70000, 56, 75, 0 },	/* SVGA		*/
+	{ 30000, 70000, 60, 60, 0 }
+};
+
+static struct display global_disp;
 static struct fb_info fb_info;
 static struct acornfb_par current_par;
+static struct fb_var_screeninfo __initdata init_var = {};
 
-static int
-acornfb_open(struct fb_info *info, int user)
+extern int acornfb_depth;	/* set by setup.c */
+extern unsigned int vram_size;	/* set by setup.c */
+
+
+static struct vidc_timing {
+	u_int	h_cycle;
+	u_int	h_sync_width;
+	u_int	h_border_start;
+	u_int	h_display_start;
+	u_int	h_display_end;
+	u_int	h_border_end;
+	u_int	h_interlace;
+
+	u_int	v_cycle;
+	u_int	v_sync_width;
+	u_int	v_border_start;
+	u_int	v_display_start;
+	u_int	v_display_end;
+	u_int	v_border_end;
+
+	u_int	control;
+
+	/* VIDC20 only */
+	u_int	pll_ctl;
+} current_vidc;
+
+#ifdef HAS_VIDC
+
+#define VID_CTL_VS_NVSYNC	(1 << 3)
+#define VID_CTL_HS_NHSYNC	(1 << 2)
+#define VID_CTL_24MHz		(0)
+#define VID_CTL_25MHz		(1)
+#define VID_CTL_36MHz		(2)
+
+#define VIDC_CTRL_INTERLACE	(1 << 6)
+#define VIDC_CTRL_FIFO_0_4	(0 << 4)
+#define VIDC_CTRL_FIFO_1_5	(1 << 4)
+#define VIDC_CTRL_FIFO_2_6	(2 << 4)
+#define VIDC_CTRL_FIFO_3_7	(3 << 4)
+#define VIDC_CTRL_1BPP		(0 << 2)
+#define VIDC_CTRL_2BPP		(1 << 2)
+#define VIDC_CTRL_4BPP		(2 << 2)
+#define VIDC_CTRL_8BPP		(3 << 2)
+#define VIDC_CTRL_DIV3		(0 << 0)
+#define VIDC_CTRL_DIV2		(1 << 0)
+#define VIDC_CTRL_DIV1_5	(2 << 0)
+#define VIDC_CTRL_DIV1		(3 << 0)
+
+/* CTL     VIDC	Actual
+ * 24.000  0	 8.000
+ * 25.175  0	 8.392
+ * 36.000  0	12.000
+ * 24.000  1	12.000
+ * 25.175  1	12.588
+ * 24.000  2	16.000
+ * 25.175  2	16.783
+ * 36.000  1	18.000
+ * 24.000  3	24.000
+ * 36.000  2	24.000
+ * 25.175  3	25.175
+ * 36.000  3	36.000
+ */
+static struct pixclock {
+	u_long	min_clock;
+	u_long	max_clock;
+	u_int	vidc_ctl;
+	u_int	vid_ctl;
+} pixclocks[] = {
+	/* we allow +/-1% on these */
+	{ 123750, 126250, VIDC_CTRL_DIV3,   VID_CTL_24MHz },	/*  8.000MHz */
+	{  82500,  84167, VIDC_CTRL_DIV2,   VID_CTL_24MHz },	/* 12.000MHz */
+	{  61875,  63125, VIDC_CTRL_DIV1_5, VID_CTL_24MHz },	/* 16.000MHz */
+	{  41250,  42083, VIDC_CTRL_DIV1,   VID_CTL_24MHz },	/* 24.000MHz */
+#ifdef CONFIG_ARCH_A5K
+	{ 117974, 120357, VIDC_CTRL_DIV3,   VID_CTL_25MHz },	/*  8.392MHz */
+	{  78649,  80238, VIDC_CTRL_DIV2,   VID_CTL_25MHz },	/* 12.588MHz */
+	{  58987,  60178, VIDC_CTRL_DIV1_5, VID_CTL_25MHz },	/* 16.588MHz */
+	{  55000,  56111, VIDC_CTRL_DIV2,   VID_CTL_36MHz },	/* 18.000MHz */
+	{  39325,  40119, VIDC_CTRL_DIV1,   VID_CTL_25MHz },	/* 25.175MHz */
+	{  27500,  28055, VIDC_CTRL_DIV1,   VID_CTL_36MHz },	/* 36.000MHz */
+#endif
+	{ 0, }
+};
+
+static struct pixclock *
+acornfb_valid_pixrate(u_long pixclock)
 {
-	MOD_INC_USE_COUNT;
-	return 0;
+	u_int i;
+
+	for (i = 0; pixclocks[i].min_clock; i++)
+		if (pixclock > pixclocks[i].min_clock &&
+		    pixclock < pixclocks[i].max_clock)
+			return pixclocks + i;
+
+	return NULL;
 }
 
-static int
-acornfb_release(struct fb_info *info, int user)
+/* VIDC Rules:
+ * hcr  : must be even (interlace, hcr/2 must be even)
+ * hswr : must be even
+ * hdsr : must be odd
+ * hder : must be odd
+ *
+ * vcr  : must be odd
+ * vswr : >= 1
+ * vdsr : >= 1
+ * vder : >= vdsr
+ * if interlaced, then hcr/2 must be even
+ */
+static void
+acornfb_set_timing(struct fb_var_screeninfo *var)
 {
-	MOD_DEC_USE_COUNT;
-	return 0;
+	struct pixclock *pclk;
+	struct vidc_timing vidc;
+	u_int horiz_correction;
+	u_int sync_len, display_start, display_end, cycle;
+	u_int is_interlaced;
+	u_int vid_ctl, vidc_ctl;
+	u_int bandwidth;
+
+	memset(&vidc, 0, sizeof(vidc));
+
+	pclk = acornfb_valid_pixrate(var->pixclock);
+	vidc_ctl = pclk->vidc_ctl;
+	vid_ctl  = pclk->vid_ctl;
+
+	bandwidth = var->pixclock * 8 / var->bits_per_pixel;
+	/* 25.175, 4bpp = 79.444ns per byte, 317.776ns per word: fifo = 2,6 */
+	if (bandwidth > 71750)
+		vidc_ctl |= VIDC_CTRL_FIFO_2_6;
+	else if (bandwidth > 35875)
+		vidc_ctl |= VIDC_CTRL_FIFO_1_5;
+	else
+		vidc_ctl |= VIDC_CTRL_FIFO_0_4;
+
+	switch (var->bits_per_pixel) {
+	case 1:
+		horiz_correction = 19;
+		vidc_ctl |= VIDC_CTRL_1BPP;
+		break;
+
+	case 2:
+		horiz_correction = 11;
+		vidc_ctl |= VIDC_CTRL_2BPP;
+		break;
+
+	case 4:
+		horiz_correction = 7;
+		vidc_ctl |= VIDC_CTRL_4BPP;
+		break;
+
+	default:
+	case 8:
+		horiz_correction = 5;
+		vidc_ctl |= VIDC_CTRL_8BPP;
+		break;
+	}
+
+	if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
+		vid_ctl |= VID_CTL_HS_NHSYNC;
+
+	if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
+		vid_ctl |= VID_CTL_VS_NVSYNC;
+
+	sync_len	= var->hsync_len;
+	display_start	= sync_len + var->left_margin;
+	display_end	= display_start + var->xres;
+	cycle		= display_end + var->right_margin;
+
+	/* if interlaced, then hcr/2 must be even */
+	is_interlaced = (var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED;
+
+	if (is_interlaced) {
+		vidc_ctl |= VIDC_CTRL_INTERLACE;
+		if (cycle & 2) {
+			cycle += 2;
+			var->right_margin += 2;
+		}
+	}
+
+	vidc.h_cycle		= (cycle - 2) / 2;
+	vidc.h_sync_width	= (sync_len - 2) / 2;
+	vidc.h_border_start	= (display_start - 1) / 2;
+	vidc.h_display_start	= (display_start - horiz_correction) / 2;
+	vidc.h_display_end	= (display_end - horiz_correction) / 2;
+	vidc.h_border_end	= (display_end - 1) / 2;
+	vidc.h_interlace	= (vidc.h_cycle + 1) / 2;
+
+	sync_len	= var->vsync_len;
+	display_start	= sync_len + var->upper_margin;
+	display_end	= display_start + var->yres;
+	cycle		= display_end + var->lower_margin;
+
+	if (is_interlaced)
+		cycle = (cycle - 3) / 2;
+	else
+		cycle = cycle - 1;
+
+	vidc.v_cycle		= cycle;
+	vidc.v_sync_width	= sync_len - 1;
+	vidc.v_border_start	= display_start - 1;
+	vidc.v_display_start	= vidc.v_border_start;
+	vidc.v_display_end	= display_end - 1;
+	vidc.v_border_end	= vidc.v_display_end;
+
+#ifdef CONFIG_ARCH_A5K
+	outb(vid_ctl, IOEB_VID_CTL);
+#endif
+	if (memcmp(&current_vidc, &vidc, sizeof(vidc))) {
+		current_vidc = vidc;
+
+		outl(0xe0000000 | vidc_ctl,			IO_VIDC_BASE);
+		outl(0x80000000 | (vidc.h_cycle << 14),		IO_VIDC_BASE);
+		outl(0x84000000 | (vidc.h_sync_width << 14),	IO_VIDC_BASE);
+		outl(0x88000000 | (vidc.h_border_start << 14),	IO_VIDC_BASE);
+		outl(0x8c000000 | (vidc.h_display_start << 14),	IO_VIDC_BASE);
+		outl(0x90000000 | (vidc.h_display_end << 14),	IO_VIDC_BASE);
+		outl(0x94000000 | (vidc.h_border_end << 14),	IO_VIDC_BASE);
+		outl(0x98000000,				IO_VIDC_BASE);
+		outl(0x9c000000 | (vidc.h_interlace << 14),	IO_VIDC_BASE);
+		outl(0xa0000000 | (vidc.v_cycle << 14),		IO_VIDC_BASE);
+		outl(0xa4000000 | (vidc.v_sync_width << 14),	IO_VIDC_BASE);
+		outl(0xa8000000 | (vidc.v_border_start << 14),	IO_VIDC_BASE);
+		outl(0xac000000 | (vidc.v_display_start << 14),	IO_VIDC_BASE);
+		outl(0xb0000000 | (vidc.v_display_end << 14),	IO_VIDC_BASE);
+		outl(0xb4000000 | (vidc.v_border_end << 14),	IO_VIDC_BASE);
+		outl(0xb8000000,				IO_VIDC_BASE);
+		outl(0xbc000000,				IO_VIDC_BASE);
+	}
+#ifdef DEBUG_MODE_SELECTION
+	printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres,
+	       var->yres, var->bits_per_pixel);
+	printk(KERN_DEBUG " H-cycle          : %d\n", vidc.h_cycle);
+	printk(KERN_DEBUG " H-sync-width     : %d\n", vidc.h_sync_width);
+	printk(KERN_DEBUG " H-border-start   : %d\n", vidc.h_border_start);
+	printk(KERN_DEBUG " H-display-start  : %d\n", vidc.h_display_start);
+	printk(KERN_DEBUG " H-display-end    : %d\n", vidc.h_display_end);
+	printk(KERN_DEBUG " H-border-end     : %d\n", vidc.h_border_end);
+	printk(KERN_DEBUG " H-interlace      : %d\n", vidc.h_interlace);
+	printk(KERN_DEBUG " V-cycle          : %d\n", vidc.v_cycle);
+	printk(KERN_DEBUG " V-sync-width     : %d\n", vidc.v_sync_width);
+	printk(KERN_DEBUG " V-border-start   : %d\n", vidc.v_border_start);
+	printk(KERN_DEBUG " V-display-start  : %d\n", vidc.v_display_start);
+	printk(KERN_DEBUG " V-display-end    : %d\n", vidc.v_display_end);
+	printk(KERN_DEBUG " V-border-end     : %d\n", vidc.v_border_end);
+	printk(KERN_DEBUG " VIDC Ctrl (E)    : 0x%08X\n", vidc_ctl);
+	printk(KERN_DEBUG " IOEB Ctrl        : 0x%08X\n", vid_ctl);
+#endif
+}
+
+static inline void
+acornfb_palette_write(u_int regno, union palette pal)
+{
+	outl(pal.p, IO_VIDC_BASE);
+}
+
+static inline union palette
+acornfb_palette_encode(u_int regno, u_int red, u_int green, u_int blue,
+		       u_int trans)
+{
+	union palette pal;
+
+	pal.p = 0;
+	pal.vidc.reg   = regno;
+	pal.vidc.red   = red >> 12;
+	pal.vidc.green = green >> 12;
+	pal.vidc.blue  = blue >> 12;
+	return pal;
 }
 
 static void
-acornfb_encode_var(struct fb_var_screeninfo *var, struct acornfb_par *par)
+acornfb_palette_decode(u_int regno, u_int *red, u_int *green, u_int *blue,
+		       u_int *trans)
 {
-	var->xres		= par->xres;
-	var->yres		= par->yres;
-	var->xres_virtual	= par->xres;
-	var->yres_virtual	= par->yres;
-	var->xoffset		= 0;
-	var->yoffset		= 0;
-	var->bits_per_pixel	= par->bits_per_pixel;
-	var->grayscale		= 0;
-	var->red.offset		= 0;
-	var->red.length		= 8;
-	var->red.msb_right	= 0;
-	var->green.offset	= 0;
-	var->green.length	= 8;
-	var->green.msb_right	= 0;
-	var->blue.offset	= 0;
-	var->blue.length	= 8;
-	var->blue.msb_right	= 0;
-	var->transp.offset	= 0;
-	var->transp.length	= 4;
-	var->transp.msb_right	= 0;
-	var->nonstd		= 0;
-	var->activate		= FB_ACTIVATE_NOW;
-	var->height		= -1;
-	var->width		= -1;
-	var->vmode		= FB_VMODE_NONINTERLACED;
-	var->pixclock		= 1;
-	var->sync		= 0;
-	var->left_margin	= 0;
-	var->right_margin	= 0;
-	var->upper_margin	= 0;
-	var->lower_margin	= 0;
-	var->hsync_len		= 0;
-	var->vsync_len		= 0;
+	*red   = EXTEND4(current_par.palette[regno].vidc.red);
+	*green = EXTEND4(current_par.palette[regno].vidc.green);
+	*blue  = EXTEND4(current_par.palette[regno].vidc.blue);
+	*trans = current_par.palette[regno].vidc.trans ? -1 : 0;
 }
+#endif
 
-static int
-acornfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
+#ifdef HAS_VIDC20
+/*
+ * VIDC20 registers
+ */
+#define VIDC20_CTRL		0xe0000000
+#define VIDC20_CTRL_PIX_VCLK	(0 << 0)
+#define VIDC20_CTRL_PIX_HCLK	(1 << 0)
+#define VIDC20_CTRL_PIX_RCLK	(2 << 0)
+#define VIDC20_CTRL_PIX_CK	(0 << 2)
+#define VIDC20_CTRL_PIX_CK2	(1 << 2)
+#define VIDC20_CTRL_PIX_CK3	(2 << 2)
+#define VIDC20_CTRL_PIX_CK4	(3 << 2)
+#define VIDC20_CTRL_PIX_CK5	(4 << 2)
+#define VIDC20_CTRL_PIX_CK6	(5 << 2)
+#define VIDC20_CTRL_PIX_CK7	(6 << 2)
+#define VIDC20_CTRL_PIX_CK8	(7 << 2)
+#define VIDC20_CTRL_1BPP	(0 << 5)
+#define VIDC20_CTRL_2BPP	(1 << 5)
+#define VIDC20_CTRL_4BPP	(2 << 5)
+#define VIDC20_CTRL_8BPP	(3 << 5)
+#define VIDC20_CTRL_16BPP	(4 << 5)
+#define VIDC20_CTRL_32BPP	(6 << 5)
+#define VIDC20_CTRL_FIFO_NS	(0 << 8)
+#define VIDC20_CTRL_FIFO_4	(1 << 8)
+#define VIDC20_CTRL_FIFO_8	(2 << 8)
+#define VIDC20_CTRL_FIFO_12	(3 << 8)
+#define VIDC20_CTRL_FIFO_16	(4 << 8)
+#define VIDC20_CTRL_FIFO_20	(5 << 8)
+#define VIDC20_CTRL_FIFO_24	(6 << 8)
+#define VIDC20_CTRL_FIFO_28	(7 << 8)
+#define VIDC20_CTRL_INT		(1 << 12)
+#define VIDC20_CTRL_DUP		(1 << 13)
+#define VIDC20_CTRL_PDOWN	(1 << 14)
+
+#define VIDC20_ECTL		0xc0000000
+#define VIDC20_ECTL_REG(x)	((x) & 0xf3)
+#define VIDC20_ECTL_ECK		(1 << 2)
+#define VIDC20_ECTL_REDPED	(1 << 8)
+#define VIDC20_ECTL_GREENPED	(1 << 9)
+#define VIDC20_ECTL_BLUEPED	(1 << 10)
+#define VIDC20_ECTL_DAC		(1 << 12)
+#define VIDC20_ECTL_LCDGS	(1 << 13)
+#define VIDC20_ECTL_HRM		(1 << 14)
+
+#define VIDC20_ECTL_HS_MASK	(3 << 16)
+#define VIDC20_ECTL_HS_HSYNC	(0 << 16)
+#define VIDC20_ECTL_HS_NHSYNC	(1 << 16)
+#define VIDC20_ECTL_HS_CSYNC	(2 << 16)
+#define VIDC20_ECTL_HS_NCSYNC	(3 << 16)
+
+#define VIDC20_ECTL_VS_MASK	(3 << 18)
+#define VIDC20_ECTL_VS_VSYNC	(0 << 18)
+#define VIDC20_ECTL_VS_NVSYNC	(1 << 18)
+#define VIDC20_ECTL_VS_CSYNC	(2 << 18)
+#define VIDC20_ECTL_VS_NCSYNC	(3 << 18)
+
+#define VIDC20_DCTL		0xf0000000
+/* 0-9 = number of words in scanline */
+#define VIDC20_DCTL_SNA		(1 << 12)
+#define VIDC20_DCTL_HDIS	(1 << 13)
+#define VIDC20_DCTL_BUS_NS	(0 << 16)
+#define VIDC20_DCTL_BUS_D31_0	(1 << 16)
+#define VIDC20_DCTL_BUS_D63_32	(2 << 16)
+#define VIDC20_DCTL_BUS_D63_0	(3 << 16)
+#define VIDC20_DCTL_VRAM_DIS	(0 << 18)
+#define VIDC20_DCTL_VRAM_PXCLK	(1 << 18)
+#define VIDC20_DCTL_VRAM_PXCLK2	(2 << 18)
+#define VIDC20_DCTL_VRAM_PXCLK4	(3 << 18)
+
+#define acornfb_valid_pixrate(rate) (1)
+
+/*
+ * Try to find the best PLL parameters for the pixel clock.
+ * This algorithm seems to give best predictable results,
+ * and produces the same values as detailed in the VIDC20
+ * data sheet.
+ */
+static inline u_int
+acornfb_vidc20_find_pll(u_int pixclk)
 {
-	struct acornfb_par *par = &current_par;
-	unsigned int line_length;
+	u_int r, best_r = 2, best_v = 2;
+	int best_d = 0x7fffffff;
 
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-	strcpy(fix->id, "Acorn");
+	for (r = 2; r <= 32; r++) {
+		u_int rr, v, p;
+		int d;
 
-	line_length = par->xres * par->bits_per_pixel / 8;
+		rr = 41667 * r;
 
-	fix->smem_start	 = (char *)SCREEN2_BASE;
-	fix->smem_len	 = (((line_length * par->yres) - 1) | (PAGE_SIZE - 1)) + 1;
-	fix->type	 = FB_TYPE_PACKED_PIXELS;
-	fix->type_aux	 = 0;
-	fix->visual	 = FB_VISUAL_PSEUDOCOLOR;
-	fix->xpanstep	 = 0;
-	fix->ypanstep	 = 0;
-	fix->ywrapstep	 = 1;
-	fix->line_length = line_length;
-	fix->accel	 = FB_ACCEL_NONE;
+		v = (rr + pixclk / 2) / pixclk;
 
-	return 0;
+		if (v > 32 || v < 2)
+			continue;
+
+		p = (rr + v / 2) / v;
+
+		d = pixclk - p;
+
+		if (d < 0)
+			d = -d;
+
+		if (d < best_d) {
+			best_d = d;
+			best_v = v - 1;
+			best_r = r - 1;
+		}
+
+		if (d == 0)
+			break;
+	}
+
+	return best_v << 8 | best_r;
 }
 
-static int
-acornfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+static inline void
+acornfb_vidc20_find_rates(struct vidc_timing *vidc,
+			  struct fb_var_screeninfo *var)
 {
-	if (con == -1) {
-		acornfb_encode_var(var, &current_par);
+	u_int div, bandwidth;
+
+	/* Select pixel-clock divisor to keep PLL in range */
+	div = var->pixclock / 9090; /*9921*/
+
+	/* Limit divisor */
+	if (div == 0)
+		div = 1;
+	if (div > 8)
+		div = 8;
+
+	/* Encode divisor to VIDC20 setting */
+	switch (div) {
+	case 1:	vidc->control |= VIDC20_CTRL_PIX_CK;  break;
+	case 2:	vidc->control |= VIDC20_CTRL_PIX_CK2; break;
+	case 3:	vidc->control |= VIDC20_CTRL_PIX_CK3; break;
+	case 4:	vidc->control |= VIDC20_CTRL_PIX_CK4; break;
+	case 5:	vidc->control |= VIDC20_CTRL_PIX_CK5; break;
+	case 6:	vidc->control |= VIDC20_CTRL_PIX_CK6; break;
+	case 7:	vidc->control |= VIDC20_CTRL_PIX_CK7; break;
+	case 8: vidc->control |= VIDC20_CTRL_PIX_CK8; break;
+	}
+
+	/* Calculate bandwidth */
+	bandwidth = var->pixclock * 8 / var->bits_per_pixel;
+
+	/* Encode bandwidth as VIDC20 setting */
+	if (bandwidth > 16667*2)
+		vidc->control |= VIDC20_CTRL_FIFO_16;
+	else if (bandwidth > 13333*2)
+		vidc->control |= VIDC20_CTRL_FIFO_20;
+	else if (bandwidth > 11111*2)
+		vidc->control |= VIDC20_CTRL_FIFO_24;
+	else
+		vidc->control |= VIDC20_CTRL_FIFO_28;
+
+	/* Find the PLL values */
+	vidc->pll_ctl  = acornfb_vidc20_find_pll(var->pixclock / div);
+}
+
+/* VIDC20 has a different set of rules from the VIDC:
+ *  hcr  : must be multiple of 4
+ *  hswr : must be even
+ *  hdsr : must be even
+ *  hder : must be even
+ *  vcr  : >= 2, (interlace, must be odd)
+ *  vswr : >= 1
+ *  vdsr : >= 1
+ *  vder : >= vdsr
+ */
+static void
+acornfb_set_timing(struct fb_var_screeninfo *var)
+{
+	struct vidc_timing vidc;
+	u_int vcr, fsize;
+	u_int ext_ctl, dat_ctl;
+	u_int words_per_line;
+
+	memset(&vidc, 0, sizeof(vidc));
+
+	vidc.h_sync_width	= var->hsync_len - 8;
+	vidc.h_border_start	= vidc.h_sync_width + var->left_margin + 8 - 12;
+	vidc.h_display_start	= vidc.h_border_start + 12 - 18;
+	vidc.h_display_end	= vidc.h_display_start + var->xres;
+	vidc.h_border_end	= vidc.h_display_end + 18 - 12;
+	vidc.h_cycle		= vidc.h_border_end + var->right_margin + 12 - 8;
+	vidc.h_interlace	= vidc.h_cycle / 2;
+	vidc.v_sync_width	= var->vsync_len - 1;
+	vidc.v_border_start	= vidc.v_sync_width + var->upper_margin;
+	vidc.v_display_start	= vidc.v_border_start;
+	vidc.v_display_end	= vidc.v_display_start + var->yres;
+	vidc.v_border_end	= vidc.v_display_end;
+	vidc.control		= VIDC20_CTRL_PIX_VCLK;
+
+	vcr = var->vsync_len + var->upper_margin + var->yres +
+	      var->lower_margin;
+
+	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+		vidc.v_cycle = (vcr - 3) / 2;
+		vidc.control |= VIDC20_CTRL_INT;
 	} else
-		*var = fb_display[con].var;
-	return 0;
+		vidc.v_cycle = vcr - 2;
+
+	switch (var->bits_per_pixel) {
+	case  1: vidc.control |= VIDC20_CTRL_1BPP;	break;
+	case  2: vidc.control |= VIDC20_CTRL_2BPP;	break;
+	case  4: vidc.control |= VIDC20_CTRL_4BPP;	break;
+	default:
+	case  8: vidc.control |= VIDC20_CTRL_8BPP;	break;
+	case 16: vidc.control |= VIDC20_CTRL_16BPP;	break;
+	case 32: vidc.control |= VIDC20_CTRL_32BPP;	break;
+	}
+
+	acornfb_vidc20_find_rates(&vidc, var);
+	fsize = var->vsync_len + var->upper_margin + var->lower_margin - 1;
+
+	if (memcmp(&current_vidc, &vidc, sizeof(vidc))) {
+		current_vidc = vidc;
+
+		outl(VIDC20_CTRL| vidc.control,		IO_VIDC_BASE);
+		outl(0xd0000000 | vidc.pll_ctl,		IO_VIDC_BASE);
+		outl(0x80000000 | vidc.h_cycle,		IO_VIDC_BASE);
+		outl(0x81000000 | vidc.h_sync_width,	IO_VIDC_BASE);
+		outl(0x82000000 | vidc.h_border_start,	IO_VIDC_BASE);
+		outl(0x83000000 | vidc.h_display_start,	IO_VIDC_BASE);
+		outl(0x84000000 | vidc.h_display_end,	IO_VIDC_BASE);
+		outl(0x85000000 | vidc.h_border_end,	IO_VIDC_BASE);
+		outl(0x86000000,			IO_VIDC_BASE);
+		outl(0x87000000 | vidc.h_interlace,	IO_VIDC_BASE);
+		outl(0x90000000 | vidc.v_cycle,		IO_VIDC_BASE);
+		outl(0x91000000 | vidc.v_sync_width,	IO_VIDC_BASE);
+		outl(0x92000000 | vidc.v_border_start,	IO_VIDC_BASE);
+		outl(0x93000000 | vidc.v_display_start,	IO_VIDC_BASE);
+		outl(0x94000000 | vidc.v_display_end,	IO_VIDC_BASE);
+		outl(0x95000000 | vidc.v_border_end,	IO_VIDC_BASE);
+		outl(0x96000000,			IO_VIDC_BASE);
+		outl(0x97000000,			IO_VIDC_BASE);
+	}
+
+	outl(fsize, IOMD_FSIZE);
+
+	ext_ctl = VIDC20_ECTL_DAC | VIDC20_ECTL_REG(3);
+
+	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+		ext_ctl |= VIDC20_ECTL_HS_HSYNC;
+	else
+		ext_ctl |= VIDC20_ECTL_HS_NHSYNC;
+
+	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+		ext_ctl |= VIDC20_ECTL_VS_VSYNC;
+	else
+		ext_ctl |= VIDC20_ECTL_VS_NVSYNC;
+
+	outl(VIDC20_ECTL | ext_ctl, IO_VIDC_BASE);
+
+	words_per_line = var->xres * var->bits_per_pixel / 32;
+
+	if (current_par.using_vram && current_par.screen_size == 2048*1024)
+		words_per_line /= 2;
+
+	/* RiscPC doesn't use the VIDC's VRAM control. */
+	dat_ctl = VIDC20_DCTL_VRAM_DIS | VIDC20_DCTL_SNA | words_per_line;
+
+	/* The data bus width is dependent on both the type
+	 * and amount of video memory.
+	 *     DRAM	32bit low
+	 * 1MB VRAM	32bit
+	 * 2MB VRAM	64bit
+	 */
+	if (current_par.using_vram && current_par.vram_half_sam == 2048) {
+		dat_ctl |= VIDC20_DCTL_BUS_D63_0;
+	} else 
+		dat_ctl |= VIDC20_DCTL_BUS_D31_0;
+
+	outl(VIDC20_DCTL | dat_ctl, IO_VIDC_BASE);
+
+#ifdef DEBUG_MODE_SELECTION
+	printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres,
+	       var->yres, var->bits_per_pixel);
+	printk(KERN_DEBUG " H-cycle          : %d\n", vidc.h_cycle);
+	printk(KERN_DEBUG " H-sync-width     : %d\n", vidc.h_sync_width);
+	printk(KERN_DEBUG " H-border-start   : %d\n", vidc.h_border_start);
+	printk(KERN_DEBUG " H-display-start  : %d\n", vidc.h_display_start);
+	printk(KERN_DEBUG " H-display-end    : %d\n", vidc.h_display_end);
+	printk(KERN_DEBUG " H-border-end     : %d\n", vidc.h_border_end);
+	printk(KERN_DEBUG " H-interlace      : %d\n", vidc.h_interlace);
+	printk(KERN_DEBUG " V-cycle          : %d\n", vidc.v_cycle);
+	printk(KERN_DEBUG " V-sync-width     : %d\n", vidc.v_sync_width);
+	printk(KERN_DEBUG " V-border-start   : %d\n", vidc.v_border_start);
+	printk(KERN_DEBUG " V-display-start  : %d\n", vidc.v_display_start);
+	printk(KERN_DEBUG " V-display-end    : %d\n", vidc.v_display_end);
+	printk(KERN_DEBUG " V-border-end     : %d\n", vidc.v_border_end);
+	printk(KERN_DEBUG " Ext Ctrl  (C)    : 0x%08X\n", ext_ctl);
+	printk(KERN_DEBUG " PLL Ctrl  (D)    : 0x%08X\n", vidc.pll_ctl);
+	printk(KERN_DEBUG " Ctrl      (E)    : 0x%08X\n", vidc.control);
+	printk(KERN_DEBUG " Data Ctrl (F)    : 0x%08X\n", dat_ctl);
+	printk(KERN_DEBUG " Fsize            : 0x%08X\n", fsize);
+#endif
 }
 
-static int
-acornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+static inline void
+acornfb_palette_write(u_int regno, union palette pal)
 {
-	return 0;
+	outl(0x10000000 | regno, IO_VIDC_BASE);
+	outl(pal.p, IO_VIDC_BASE);
+}
+
+static inline union palette
+acornfb_palette_encode(u_int regno, u_int red, u_int green, u_int blue,
+		       u_int trans)
+{
+	union palette pal;
+
+	pal.p = 0;
+	pal.vidc20.red   = red >> 8;
+	pal.vidc20.green = green >> 8;
+	pal.vidc20.blue  = blue >> 8;
+	return pal;
 }
 
 static void
-acornfb_set_disp(int con)
+acornfb_palette_decode(u_int regno, u_int *red, u_int *green, u_int *blue,
+		       u_int *trans)
 {
-	struct fb_fix_screeninfo fix;
-	struct display *display;
+	*red   = EXTEND8(current_par.palette[regno].vidc20.red);
+	*green = EXTEND8(current_par.palette[regno].vidc20.green);
+	*blue  = EXTEND8(current_par.palette[regno].vidc20.blue);
+	*trans = EXTEND4(current_par.palette[regno].vidc20.ext);
+}
+#endif
 
-	if (con >= 0)
-		display = &fb_display[con];
+/*
+ * Before selecting the timing parameters, adjust
+ * the resolution to fit the rules.
+ */
+static void
+acornfb_pre_adjust_timing(struct fb_var_screeninfo *var, int con)
+{
+	u_int font_line_len;
+	u_int fontht;
+	u_int sam_size, min_size, size;
+	u_int nr_y;
+
+	/* xres must be even */
+	var->xres = (var->xres + 1) & ~1;
+
+	/*
+	 * We don't allow xres_virtual to differ from xres
+	 */
+	var->xres_virtual = var->xres;
+	var->xoffset = 0;
+
+	/*
+	 * Find the font height
+	 */
+	if (con == -1)
+		fontht = fontheight(&global_disp);
 	else
-		display = &disp;
+		fontht = fontheight(fb_display + con);
 
-	current_par.xres = 8 * ORIG_VIDEO_COLS;
-	current_par.yres = 8 * ORIG_VIDEO_LINES;
-	current_par.bits_per_pixel = 8;
-	current_par.palette_size = MAX_VIDC20_PALETTE;
-
-	acornfb_get_fix(&fix, con, 0);
-
-	acornfb_get_var(&display->var, con, 0);
-
-	display->cmap.start	= 0;
-	display->cmap.len	= 0;
-	display->cmap.red	= NULL;
-	display->cmap.green	= NULL;
-	display->cmap.blue	= NULL;
-	display->cmap.transp	= NULL;
-	display->screen_base	= fix.smem_start;
-	display->visual		= fix.visual;
-	display->type		= fix.type;
-	display->type_aux	= fix.type_aux;
-	display->ypanstep	= fix.ypanstep;
-	display->ywrapstep	= fix.ywrapstep;
-	display->line_length	= fix.line_length;
-	display->can_soft_blank	= 0;
-	display->inverse	= 0;
+	if (fontht == 0)
+		fontht = 8;
 
-	outl(SCREEN_START, VDMA_START);
-	outl(SCREEN_START + fix.smem_len - VDMA_XFERSIZE, VDMA_END);
-	outl(SCREEN_START, VDMA_INIT);
+	if (current_par.using_vram)
+		sam_size = current_par.vram_half_sam * 2;
+	else
+		sam_size = 16;
 
-	switch (display->var.bits_per_pixel) {
-#ifdef FBCON_HAS_MFB
-	case 1:
-		display->dispsw = &fbcon_mfb;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB2
-	case 2:
-		display->dispsw = &fbcon_cfb2;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB4
-	case 4:
-		display->dispsw = &fbcon_cfb4;
-		break;
+	/*
+	 * Now, find a value for yres_virtual which allows
+	 * us to do ywrap scrolling.  The value of
+	 * yres_virtual must be such that the end of the
+	 * displayable frame buffer must be aligned with
+	 * the start of a font line.
+	 */
+	font_line_len = var->xres * var->bits_per_pixel * fontht / 8;
+	min_size = var->xres * var->yres * var->bits_per_pixel / 8;
+
+	/* Find int 'y', such that y * fll == s * sam < maxsize
+	 * y = s * sam / fll; s = maxsize / sam
+	 */
+	for (size = current_par.screen_size; min_size <= size;
+	     size -= sam_size) {
+		nr_y = size / font_line_len;
+
+		if (nr_y * font_line_len == size)
+			break;
+	}
+
+	if (min_size > size) {
+		/*
+		 * failed, use ypan
+		 */
+		size = current_par.screen_size;
+		var->yres_virtual = size / (font_line_len / fontht);
+	} else
+		var->yres_virtual = nr_y * fontht;
+
+	current_par.screen_end = current_par.screen_base_p + size;
+
+	/*
+	 * Fix yres & yoffset if needed.
+	 */
+	if (var->yres > var->yres_virtual)
+		var->yres = var->yres_virtual;
+
+	if (var->vmode & FB_VMODE_YWRAP) {
+		if (var->yoffset > var->yres_virtual)
+			var->yoffset = var->yres_virtual;
+	} else {
+		if (var->yoffset + var->yres > var->yres_virtual)
+			var->yoffset = var->yres_virtual - var->yres;
+	}
+}
+
+/*
+ * After selecting the timing parameters, adjust
+ * the timing to suit the chip.
+ * NOTE! Only minor adjustments should be made here.
+ */
+static void
+acornfb_post_adjust_timing(struct fb_var_screeninfo *var)
+{
+	/* hsync_len must be even */
+	var->hsync_len = (var->hsync_len + 1) & ~1;
+
+#ifdef HAS_VIDC
+	/* left_margin must be odd */
+	if ((var->left_margin & 1) == 0) {
+		var->left_margin -= 1;
+		var->right_margin += 1;
+	}
+
+	/* right_margin must be odd */
+	var->right_margin |= 1;
+#elif defined(HAS_VIDC20)
+	/* left_margin must be even */
+	if (var->left_margin & 1) {
+		var->left_margin += 1;
+		var->right_margin -= 1;
+	}
+
+	/* right_margin must be even */
+	if (var->right_margin & 1)
+		var->right_margin += 1;
 #endif
-#ifdef FBCON_HAS_CFB8
-	case 8:
-		display->dispsw = &fbcon_cfb8;
-		break;
+
+	if (var->vsync_len < 1)
+		var->vsync_len = 1;
+}
+
+static inline void
+acornfb_update_dma(struct fb_var_screeninfo *var)
+{
+	int off = (var->yoffset * var->xres_virtual *
+		   var->bits_per_pixel) >> 3;
+
+#if defined(HAS_MEMC)
+	memc_write(VDMA_INIT, off >> 2);
+#elif defined(HAS_IOMD)
+	outl(current_par.screen_base_p + off, IOMD_VIDINIT);
 #endif
-	default:
-		display->dispsw = &fbcon_dummy;
-		break;
-	}
 }
 
 static int
-acornfb_vidc20_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans, struct fb_info *info)
+acornfb_open(struct fb_info *info, int user)
 {
-	int t;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int
+acornfb_release(struct fb_info *info, int user)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
 
+static int
+acornfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+		  u_int *trans, struct fb_info *info)
+{
 	if (regno >= current_par.palette_size)
 		return 1;
-	t = current_par.palette.vidc20[regno].d.red;
-	*red = (t << 8) | t;
-	t = current_par.palette.vidc20[regno].d.green;
-	*green = (t << 8) | t;
-	t = current_par.palette.vidc20[regno].d.blue;
-	*blue = (t << 8) | t;
-	t = current_par.palette.vidc20[regno].d.ext;
-	t |= t << 4;
-	*transp = (t << 8) | t;
+
+	acornfb_palette_decode(regno, red, green, blue, trans);
+
 	return 0;
 }
 
 static int
-acornfb_vidc20_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info)
+acornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+		  u_int trans, struct fb_info *info)
 {
+	union palette pal;
+
 	if (regno >= current_par.palette_size)
 		return 1;
 
-	red >>= 8;
-	green >>= 8;
-	blue >>= 8;
-	current_par.palette.vidc20[regno].p = 0;
-	current_par.palette.vidc20[regno].d.red   = red;
-	current_par.palette.vidc20[regno].d.green = green;
-	current_par.palette.vidc20[regno].d.blue  = blue;
+	pal = acornfb_palette_encode(regno, red, green, blue, trans);
+	acornfb_palette_write(regno, pal);
+	current_par.palette[regno] = pal;
+
+	if (regno < 16) {
+		switch (info->disp->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB16
+		case 16:	/* RGB555 */
+			current_par.cmap.cfb16[regno] = (regno << 10) | (regno << 5) | regno;
+			break;
+#endif
 
-	outl(0x10000000 | regno, VIDC_BASE);
-	outl(current_par.palette.vidc20[regno].p, VIDC_BASE);
+		default:
+			break;
+		}
+	}
 
 	return 0;
 }
@@ -270,8 +930,8 @@
 {
 	int err = 0;
 
-	if (con == currcon)
-		err = fb_get_cmap(cmap, kspc, acornfb_vidc20_getcolreg, info);
+	if (con == current_par.currcon)
+		err = fb_get_cmap(cmap, kspc, acornfb_getcolreg, info);
 	else if (fb_display[con].cmap.len)
 		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
 	else
@@ -290,8 +950,8 @@
 		err = fb_alloc_cmap(&fb_display[con].cmap,
 				    current_par.palette_size, 0);
 	if (!err) {
-		if (con == currcon)
-			err = fb_set_cmap(cmap, kspc, acornfb_vidc20_setcolreg,
+		if (con == current_par.currcon)
+			err = fb_set_cmap(cmap, kspc, acornfb_setcolreg,
 					  info);
 		else
 			fb_copy_cmap(cmap, &fb_display[con].cmap,
@@ -301,13 +961,279 @@
 }
 
 static int
+acornfb_decode_var(struct fb_var_screeninfo *var, int con, int *visual)
+{
+	switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_MFB
+	case 1:
+		*visual = FB_VISUAL_MONO10;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB8
+	case 8:
+#ifdef HAS_VIDC
+		*visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+#else
+		*visual = FB_VISUAL_PSEUDOCOLOR;
+#endif
+		break;
+#endif
+#ifdef FBCON_HAS_CFB4
+	case 4:
+		*visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB2
+	case 2:
+		*visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+#endif
+	case 16:
+	case 24:
+	case 32:
+		*visual = FB_VISUAL_TRUECOLOR;
+	default:
+		return -EINVAL;
+	}
+
+	if (!acornfb_valid_pixrate(var->pixclock))
+		return -EINVAL;
+
+	/*
+	 * Adjust the resolution before using it.
+	 */
+	acornfb_pre_adjust_timing(var, con);
+
+#if defined(HAS_VIDC20)
+	var->red.length	   = 8;
+	var->transp.length = 4;
+#elif defined(HAS_VIDC)
+	var->red.length	   = 4;
+	var->transp.length = 1;
+#endif
+	var->green = var->red;
+	var->blue  = var->red;
+
+	/*
+	 * Now adjust the timing parameters
+	 */
+	acornfb_post_adjust_timing(var);
+
+	return 0;
+}
+
+static int
+acornfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
+{
+	struct display *display;
+
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id, "Acorn");
+
+	if (con >= 0)
+		display = fb_display + con;
+	else
+		display = &global_disp;
+
+	fix->smem_start	 = (char *)current_par.screen_base_p;
+	fix->smem_len	 = current_par.screen_size;
+	fix->type	 = display->type;
+	fix->type_aux	 = display->type_aux;
+	fix->xpanstep	 = 0;
+	fix->ypanstep	 = display->ypanstep;
+	fix->ywrapstep	 = display->ywrapstep;
+	fix->visual	 = display->visual;
+	fix->line_length = display->line_length;
+	fix->accel	 = FB_ACCEL_NONE;
+
+	return 0;
+}
+
+static int
+acornfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	if (con == -1) {
+		*var = global_disp.var;
+	} else
+		*var = fb_display[con].var;
+
+	return 0;
+}
+
+static int
+acornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	struct display *display;
+	int err, chgvar = 0, visual;
+
+	if (con >= 0)
+		display = fb_display + con;
+	else
+		display = &global_disp;
+
+	if (!current_par.allow_modeset && con != -1)
+		return -EINVAL;
+
+	err = acornfb_decode_var(var, con, &visual);
+	if (err)
+		return err;
+
+	switch (var->activate & FB_ACTIVATE_MASK) {
+	case FB_ACTIVATE_TEST:
+		return 0;
+
+	case FB_ACTIVATE_NXTOPEN:
+	case FB_ACTIVATE_NOW:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (con >= 0) {
+		if (display->var.xres != var->xres)
+			chgvar = 1;
+		if (display->var.yres != var->yres)
+			chgvar = 1;
+		if (display->var.xres_virtual != var->xres_virtual)
+			chgvar = 1;
+		if (display->var.yres_virtual != var->yres_virtual)
+			chgvar = 1;
+		if (memcmp(&display->var.red, &var->red, sizeof(var->red)))
+			chgvar = 1;
+		if (memcmp(&display->var.green, &var->green, sizeof(var->green)))
+			chgvar = 1;
+		if (memcmp(&display->var.blue, &var->blue, sizeof(var->blue)))
+			chgvar = 1;
+	}
+
+	display->var = *var;
+	display->var.activate &= ~FB_ACTIVATE_ALL;
+
+	if (var->activate & FB_ACTIVATE_ALL)
+		global_disp.var = display->var;
+
+	display->screen_base	= (char *)current_par.screen_base;
+	display->visual		= visual;
+	display->type		= FB_TYPE_PACKED_PIXELS;
+	display->type_aux	= 0;
+	display->ypanstep	= 1;
+	display->ywrapstep	= 1;
+	display->line_length	=
+	display->next_line      = (var->xres * var->bits_per_pixel) / 8;
+	display->can_soft_blank	= visual == FB_VISUAL_PSEUDOCOLOR ? 1 : 0;
+	display->inverse	= 0;
+
+	switch (display->var.bits_per_pixel) {
+#ifdef FBCON_HAS_MFB
+	case 1:
+		current_par.palette_size = 2;
+		display->dispsw = &fbcon_mfb;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB2
+	case 2:
+		current_par.palette_size = 4;
+		display->dispsw = &fbcon_cfb2;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB4
+	case 4:
+		current_par.palette_size = 16;
+		display->dispsw = &fbcon_cfb4;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		current_par.palette_size = VIDC_PALETTE_SIZE;
+		display->dispsw = &fbcon_cfb8;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		current_par.palette_size = VIDC_PALETTE_SIZE;
+		display->dispsw = &fbcon_cfb16;
+		display->dispsw_data = current_par.cmap.cfb16;
+		break;
+#endif
+	default:
+		display->dispsw = &fbcon_dummy;
+		break;
+	}
+
+	if (chgvar && info && info->changevar)
+		info->changevar(con);
+
+	if (con == current_par.currcon) {
+		struct fb_cmap *cmap;
+		unsigned long start, size;
+		int control;
+
+#if defined(HAS_MEMC)
+		start   = 0;
+		size    = current_par.screen_size - VDMA_XFERSIZE;
+		control = 0;
+
+		memc_write(VDMA_START, start);
+		memc_write(VDMA_END, size >> 2);
+#elif defined(HAS_IOMD)
+
+		start = current_par.screen_base_p;
+		size  = current_par.screen_end;
+
+		if (current_par.using_vram) {
+			size -= current_par.vram_half_sam;
+			control = DMA_CR_E | (current_par.vram_half_sam / 256);
+		} else {
+			size -= 16;
+			control = DMA_CR_E | DMA_CR_D | 16;
+		}
+
+		outl(start,   IOMD_VIDSTART);
+		outl(size,    IOMD_VIDEND);
+		outl(control, IOMD_VIDCR);
+#endif
+		acornfb_update_dma(var);
+
+		if (current_par.allow_modeset)
+			acornfb_set_timing(var);
+
+		if (display->cmap.len)
+			cmap = &display->cmap;
+		else
+			cmap = fb_default_cmap(current_par.palette_size);
+
+		fb_set_cmap(cmap, 1, acornfb_setcolreg, info);
+	}
+	return 0;
+}
+
+static int
 acornfb_pan_display(struct fb_var_screeninfo *var, int con,
 		    struct fb_info *info)
 {
-	if (var->xoffset || var->yoffset)
+	u_int y_bottom;
+
+	if (var->xoffset)
 		return -EINVAL;
+
+	y_bottom = var->yoffset;
+
+	if (!(var->vmode & FB_VMODE_YWRAP))
+		y_bottom += var->yres;
+
+	if (y_bottom > fb_display[con].var.yres_virtual)
+		return -EINVAL;
+
+	acornfb_update_dma(var);
+
+	fb_display[con].var.yoffset = var->yoffset;
+	if (var->vmode & FB_VMODE_YWRAP)
+		fb_display[con].var.vmode |= FB_VMODE_YWRAP;
 	else
-		return 0;
+		fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
+
+	return 0;
 }
 
 static int
@@ -329,64 +1255,652 @@
 	acornfb_ioctl
 };
 
-void
-acornfb_setup(char *options, int *ints)
+static int
+acornfb_updatevar(int con, struct fb_info *info)
 {
+	if (con == current_par.currcon)
+		acornfb_update_dma(&fb_display[con].var);
+
+	return 0;
 }
 
 static int
-acornfb_update_var(int con, struct fb_info *info)
+acornfb_switch(int con, struct fb_info *info)
 {
-	if (con == currcon) {
-		int off = fb_display[con].var.yoffset *
-			  fb_display[con].var.xres_virtual *
-			  fb_display[con].var.bits_per_pixel >> 3;
-		unsigned long base;
+	struct fb_cmap *cmap;
 
-		base = current_par.screen_base = SCREEN_START + off;
+	if (current_par.currcon >= 0) {
+		cmap = &fb_display[current_par.currcon].cmap;
 
-		outl (SCREEN_START + base, VDMA_INIT);
+		if (cmap->len)
+			fb_get_cmap(cmap, 1, acornfb_getcolreg, info);
 	}
 
-	return 0;
-}
+	current_par.currcon = con;
+
+	fb_display[con].var.activate = FB_ACTIVATE_NOW;
+
+	acornfb_set_var(&fb_display[con].var, con, info);
 
-static int
-acornfb_switch(int con, struct fb_info *info)
-{
-	currcon = con;
-	acornfb_update_var(con, info);
 	return 0;
 }
 
 static void
 acornfb_blank(int blank, struct fb_info *info)
 {
+	int i;
+
+	if (blank)
+		for (i = 0; i < current_par.palette_size; i++) {
+			union palette p;
+
+			p = acornfb_palette_encode(i, 0, 0, 0, 0);
+
+			acornfb_palette_write(i, p);
+		}
+	else
+		for (i = 0; i < current_par.palette_size; i++)
+			acornfb_palette_write(i, current_par.palette[i]);
+}
+
+/*
+ * Everything after here is initialisation!!!
+ */
+struct modey_params {
+	u_int	y_res;
+	u_int	u_margin;
+	u_int	b_margin;
+	u_int	vsync_len;
+	u_int	vf;
+};
+
+struct modex_params {
+	u_int	x_res;
+	u_int	l_margin;
+	u_int	r_margin;
+	u_int	hsync_len;
+	u_int	clock;
+	u_int	hf;
+	const struct modey_params *modey;
+};
+
+static const struct modey_params modey_640_15600[] __initdata = {
+	{  250,  38,  21,  3,  50 },	/*  640x 250, 50Hz */
+	{  256,  35,  18,  3,  50 },	/*  640x 256, 50Hz */
+	{    0,   0,   0,  0,   0 }
+};
+
+static const struct modey_params modey_640_26800[] __initdata = {
+	{  512,  18,   1,  3,  50 },	/*  640x 512, 50Hz */
+	{    0,   0,   0,  0,   0 }
+};
+
+static const struct modey_params modey_640_31500[] __initdata = {
+	{  250, 109,  88,  2,  70 },	/*  640x 250, 70Hz */
+	{  256, 106,  85,  2,  70 },	/*  640x 256, 70Hz */
+	{  352,  58,  37,  2,  70 },	/*  640x 352, 70Hz */
+	{  480,  32,  11,  2,  60 },	/*  640x 480, 60Hz */
+	{    0,   0,   0,  0,   0 }
+};
+
+static const struct modey_params modey_800_35200[] __initdata = {
+	{  600,  22,   1,  2,  56 },	/*  800x 600, 56Hz */
+	{    0,   0,   0,  0,   0 }
+};
+
+static const struct modey_params modey_896_21800[] __initdata = {
+	{  352,   9,   0,  3,  60 },	/*  896x 352, 60Hz */
+	{    0,   0,   0,  0,   0 }
+};
+
+/* everything after here is not supported */
+static const struct modey_params modey_1024_uk[] __initdata = {
+	{  768,   0,   0,  0,   0 },	/* 1024x 768 */
+	{    0,   0,   0,  0,   0 }
+};
+
+static const struct modey_params modey_1056_uk[] __initdata = {
+	{  250,   0,   0,  0,   0 },	/* 1056x 250 */
+	{  256,   0,   0,  0,   0 },	/* 1056x 256 */
+	{    0,   0,   0,  0,   0 }
+};
+
+static const struct modey_params modey_1152_uk[] __initdata = {
+	{  896,   0,   0,  0,   0 },	/* 1152x 896 */
+	{    0,   0,   0,  0,   0 }
+};
+
+static const struct modey_params modey_1280_63600[] __initdata = {
+	{ 1024,   0,   0,  0,  60 },	/* 1280x1024, 60Hz */
+	{    0,   0,   0,  0,   0 }
+};
+
+static const struct modey_params modey_1600_uk[] __initdata = {
+	{ 1280,   0,   0,  0,   0 },	/* 1600x1280 */
+	{    0,   0,   0,  0,   0 }
+};
+
+/*
+ * Horizontal video programming requirements.
+ * This table is searched for the required horizontal
+ * and required frequency, and then the tables above
+ * are then searched for the required vertical
+ * resolution.
+ *
+ * NOTE! we can match multiple entries, so we search
+ * all horizontal entries for which the hfreq is within
+ * the monitor's range.
+ */
+static const struct modex_params modex_params[] __initdata = {
+	{						/* X:  640, 15.6kHz */
+		 640,  185, 123,  76, 16000, 15625, modey_640_15600
+	},
+	{						/* X:  640, 26.8kHz */
+		 640,  113,  87,  56, 24000, 26800, modey_640_26800
+	},
+	{						/* X:  640, 31.5kHz */
+		 640,   48,  16,  96, 25175, 31500, modey_640_31500
+	},
+	{						/* X:  800, 35.2kHz */
+		 800,  101,  23, 100, 36000, 35200, modey_800_35200
+	},
+	{						/* X:  896, 21.8kHz */
+		 896,   59,  27, 118, 24000, 21800, modey_896_21800
+	},
+	{						/* X: 1024 */
+		1024,    0,   0,   0,     0,     0, modey_1024_uk
+	},
+	{						/* X: 1056 */
+		1056,    0,   0,   0,     0,     0, modey_1056_uk
+	},
+	{						/* X: 1152 */
+		1152,    0,   0,   0,     0,     0, modey_1152_uk
+	},
+	{						/* X: 1280, 63.6kHz */
+		1280,    0,   0,   0,     0, 63600, modey_1280_63600
+	},
+	{						/* X: 1600 */
+		1600,    0,   0,   0,     0,     0, modey_1600_uk
+	},
+	{
+		0,
+	}
+};
+
+__initfunc(static int
+acornfb_lookup_timing(struct fb_var_screeninfo *var))
+{
+	const struct modex_params *x;
+	const struct modey_params *y;
+
+	/*
+	 * We must adjust the resolution parameters
+	 * before selecting the timing parameters.
+	 */
+	acornfb_pre_adjust_timing(var, -1);
+
+	for (x = modex_params; x->x_res; x++) {
+
+		/*
+		 * Is this resolution one we're looking for?
+		 */
+		if (x->x_res != var->xres)
+			continue;
+
+		/*
+		 * Is the hsync frequency ok for our monitor?
+		 */
+		if (x->hf > fb_info.monspecs.hfmax ||
+		    x->hf < fb_info.monspecs.hfmin)
+			continue;
+
+		/*
+		 * Try to find a vertical resolution
+		 */
+		for (y = x->modey; y->y_res; y++) {
+			/*
+			 * Is this resolution one we're looking for?
+			 */
+			if (y->y_res != var->yres)
+				continue;
+
+			/*
+			 * Is the vsync frequency ok for our monitor?
+			 */
+			if (y->vf > fb_info.monspecs.vfmax ||
+			    y->vf < fb_info.monspecs.vfmin)
+				continue;
+
+			goto found;
+		}
+	}
+
+	var->pixclock = 0;
+
+	return -EINVAL;
+
+found:
+	/*
+	 * Why is pixclock in picoseconds?
+	 */
+	switch (x->clock) {
+	case 36000: var->pixclock =  27778;	break;
+	case 25175: var->pixclock =  39722;	break;
+	case 24000: var->pixclock =  41667;	break;
+	case 16000: var->pixclock =  62500;	break;
+	case 12000: var->pixclock =  83333;	break;
+	case  8000: var->pixclock = 125000;	break;
+	default:    var->pixclock =      0;     break;
+	}
+
+#ifdef DEBUG_MODE_SELECTION
+	printk(KERN_DEBUG "Found %dx%d at %d.%3dkHz, %dHz, pix %d\n",
+		x->x_res, y->y_res,
+		x->hf / 1000, x->hf % 1000,
+		y->vf, var->pixclock);
+#endif
+
+	var->left_margin	= x->l_margin;
+	var->right_margin	= x->r_margin;
+	var->upper_margin	= y->u_margin;
+	var->lower_margin	= y->b_margin;
+	var->hsync_len		= x->hsync_len;
+	var->vsync_len		= y->vsync_len;
+	var->sync		= 0;
+
+	/*
+	 * Now adjust the parameters we found
+	 */
+	acornfb_post_adjust_timing(var);
+
+	return 0;
 }
 
-__initfunc(unsigned long
-acornfb_init(unsigned long mem_start))
+__initfunc(static void
+acornfb_init_fbinfo(void))
 {
+	static int first = 1;
+
+	if (!first)
+		return;
+	first = 0;
+
 	strcpy(fb_info.modename, "Acorn");
-	fb_info.node		= -1;
-	fb_info.fbops		= &acornfb_ops;
-	fb_info.disp		= &disp;
-	fb_info.monspecs.hfmin	= 0;
-	fb_info.monspecs.hfmax	= 0;
-	fb_info.monspecs.vfmin	= 0;
-	fb_info.monspecs.vfmax	= 0;
-	fb_info.monspecs.dpms	= 0;
 	strcpy(fb_info.fontname, "Acorn8x8");
-	fb_info.changevar	= NULL;
-	fb_info.switch_con	= acornfb_switch;
-	fb_info.updatevar	= acornfb_update_var;
-	fb_info.blank		= acornfb_blank;
-	fb_info.flags		= FBINFO_FLAG_DEFAULT;
-
-	acornfb_set_disp(-1);
-	fb_set_cmap(fb_default_cmap(current_par.palette_size),
-		    1, acornfb_vidc20_setcolreg, &fb_info);
-	register_framebuffer(&fb_info);
 
-	return mem_start;
+	fb_info.node		   = -1;
+	fb_info.fbops		   = &acornfb_ops;
+	fb_info.disp		   = &global_disp;
+	fb_info.changevar	   = NULL;
+	fb_info.switch_con	   = acornfb_switch;
+	fb_info.updatevar	   = acornfb_updatevar;
+	fb_info.blank		   = acornfb_blank;
+	fb_info.flags		   = FBINFO_FLAG_DEFAULT;
+
+	global_disp.dispsw	   = &fbcon_dummy;
+
+	/*
+	 * setup initial parameters
+	 */
+	memset(&init_var, 0, sizeof(init_var));
+	init_var.xres		   = DEFAULT_XRES;
+	init_var.yres		   = DEFAULT_YRES;
+
+#if   defined(FBCON_HAS_CFB4)
+	init_var.bits_per_pixel	   = 4;
+#elif defined(FBCON_HAS_CFB8)
+	init_var.bits_per_pixel    = 8;
+#elif defined(FBCON_HAS_CFB2)
+	init_var.bits_per_pixel    = 2;
+#elif defined(FBCON_HAS_MFB)
+	init_var.bits_per_pixel    = 1;
+#else
+#error No suitable framebuffers configured
+#endif
+
+#if defined(HAS_VIDC20)
+	init_var.red.length	   = 8;
+	init_var.transp.length	   = 4;
+#elif defined(HAS_VIDC)
+	init_var.red.length	   = 4;
+	init_var.transp.length	   = 1;
+#endif
+	init_var.green		   = init_var.red;
+	init_var.blue		   = init_var.red;
+	init_var.nonstd		   = 0;
+	init_var.activate	   = FB_ACTIVATE_NOW;
+	init_var.height		   = -1;
+	init_var.width		   = -1;
+	init_var.vmode		   = FB_VMODE_NONINTERLACED;
+
+	current_par.dram_size	   = 0;
+	current_par.montype	   = -1;
+	current_par.dpms	   = 0;
+}
+
+/*
+ * setup acornfb options:
+ *
+ *  font:fontname
+ *	Set fontname
+ *
+ *  mon:hmin-hmax:vmin-vmax:dpms:width:height
+ *	Set monitor parameters:
+ *		hmin   = horizontal minimum frequency (Hz)
+ *		hmax   = horizontal maximum frequency (Hz)	(optional)
+ *		vmin   = vertical minimum frequency (Hz)
+ *		vmax   = vertical maximum frequency (Hz)	(optional)
+ *		dpms   = DPMS supported?			(optional)
+ *		width  = width of picture in mm.		(optional)
+ *		height = height of picture in mm.		(optional)
+ *
+ * montype:type
+ *	Set RISC-OS style monitor type:
+ *		0 (or tv)	- TV frequency
+ *		1 (or multi)	- Multi frequency
+ *		2 (or hires)	- Hi-res monochrome
+ *		3 (or vga)	- VGA
+ *		4 (or svga)	- SVGA
+ *		auto, or option missing
+ *				- try hardware detect
+ *
+ * dram:size
+ *	Set the amount of DRAM to use for the frame buffer
+ *	(even if you have VRAM).
+ *	size can optionally be followed by 'M' or 'K' for
+ *	MB or KB respectively.
+ */
+__initfunc(static void
+acornfb_parse_font(char *opt))
+{
+	strcpy(fb_info.fontname, opt);
+}
+
+__initfunc(static void
+acornfb_parse_mon(char *opt))
+{
+	fb_info.monspecs.hfmin = simple_strtoul(opt, &opt, 0);
+	if (*opt == '-')
+		fb_info.monspecs.hfmax = simple_strtoul(opt + 1, &opt, 0);
+	else
+		fb_info.monspecs.hfmax = fb_info.monspecs.hfmin;
+
+	if (*opt != ':')
+		return;
+
+	fb_info.monspecs.vfmin = simple_strtoul(opt + 1, &opt, 0);
+	if (*opt == '-')
+		fb_info.monspecs.vfmax = simple_strtoul(opt + 1, &opt, 0);
+	else
+		fb_info.monspecs.vfmax = fb_info.monspecs.vfmin;
+
+	if (*opt != ':')
+		return;
+
+	fb_info.monspecs.dpms = simple_strtoul(opt + 1, &opt, 0);
+
+	if (*opt != ':')
+		return;
+
+	init_var.width = simple_strtoul(opt + 1, &opt, 0);
+
+	if (*opt != ':')
+		return;
+
+	init_var.height = simple_strtoul(opt + 1, NULL, 0);
+}
+
+__initfunc(static void
+acornfb_parse_montype(char *opt))
+{
+	current_par.montype = -2;
+
+	if (strncmp(opt, "tv", 2) == 0) {
+		opt += 2;
+		current_par.montype = 0;
+	} else if (strncmp(opt, "multi", 5) == 0) {
+		opt += 5;
+		current_par.montype = 1;
+	} else if (strncmp(opt, "hires", 5) == 0) {
+		opt += 5;
+		current_par.montype = 2;
+	} else if (strncmp(opt, "vga", 3) == 0) {
+		opt += 3;
+		current_par.montype = 3;
+	} else if (strncmp(opt, "svga", 4) == 0) {
+		opt += 4;
+		current_par.montype = 4;
+	} else if (strncmp(opt, "auto", 4) == 0) {
+		opt += 4;
+		current_par.montype = -1;
+	} else if (isdigit(*opt))
+		current_par.montype = simple_strtoul(opt, &opt, 0);
+
+	if (current_par.montype == -2 ||
+	    current_par.montype > NR_MONTYPES) {
+		printk(KERN_ERR "acornfb: unknown monitor type: %s\n",
+			opt);
+		current_par.montype = -1;
+	} else
+	if (opt && *opt) {
+		if (strcmp(opt, ",dpms") == 0)
+			current_par.dpms = 1;
+		else
+			printk(KERN_ERR
+			       "acornfb: unknown monitor option: %s\n",
+			       opt);
+	}
+}
+
+__initfunc(static void
+acornfb_parse_dram(char *opt))
+{
+	unsigned int size;
+
+	size = simple_strtoul(opt, &opt, 0);
+
+	if (opt) {
+		switch (*opt) {
+		case 'M':
+		case 'm':
+			size *= 1024;
+		case 'K':
+		case 'k':
+			size *= 1024;
+		default:
+			break;
+		}
+	}
+
+	current_par.dram_size = size;
+}
+
+static struct options {
+	char *name;
+	void (*parse)(char *opt);
+} opt_table[] __initdata = {
+	{ "font",    acornfb_parse_font    },
+	{ "mon",     acornfb_parse_mon     },
+	{ "montype", acornfb_parse_montype },
+	{ "dram",    acornfb_parse_dram    },
+	{ NULL, NULL }
+};
+
+__initfunc(void
+acornfb_setup(char *options, int *ints))
+{
+	struct options *optp;
+	char *opt;
+
+	if (!options || !*options)
+		return;
+
+	acornfb_init_fbinfo();
+
+	for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
+		if (!*opt)
+			continue;
+
+		for (optp = opt_table; optp->name; optp++) {
+			int optlen;
+
+			optlen = strlen(optp->name);
+
+			if (strncmp(opt, optp->name, optlen) == 0 &&
+			    opt[optlen] == ':') {
+				optp->parse(opt + optlen + 1);
+				break;
+			}
+		}
+
+		if (!optp->name)
+			printk(KERN_ERR "acornfb: unknown parameter: %s\n",
+			       opt);
+	}
+}
+
+/*
+ * Detect type of monitor connected
+ *  For now, we just assume SVGA
+ */
+__initfunc(static int
+acornfb_detect_monitortype(void))
+{
+	return 4;
+}
+
+/*
+ * This enables the unused memory to be freed on older Acorn machines.
+ */
+static inline void
+free_unused_pages(unsigned int virtual_start, unsigned int virtual_end)
+{
+	int mb_freed = 0;
+
+	/*
+	 * Align addresses
+	 */
+	virtual_start = PAGE_ALIGN(virtual_start);
+	virtual_end = PAGE_ALIGN(virtual_end);
+
+	while (virtual_start < virtual_end) {
+		/*
+		 * Clear page reserved bit,
+		 * set count to 1, and free
+		 * the page.
+		 */
+		clear_bit(PG_reserved, &mem_map[MAP_NR(virtual_start)].flags);
+		atomic_set(&mem_map[MAP_NR(virtual_start)].count, 1);
+		free_page(virtual_start);
+
+		virtual_start += PAGE_SIZE;
+		mb_freed += PAGE_SIZE / 1024;
+	}
+
+	printk("acornfb: freed %dK memory\n", mb_freed);
+}
+
+__initfunc(void
+acornfb_init(void))
+{
+	unsigned long size;
+	u_int h_sync, v_sync;
+
+	acornfb_init_fbinfo();
+
+	if (current_par.montype == -1)
+		current_par.montype = acornfb_detect_monitortype();
+
+	if (current_par.montype < 0 || current_par.montype > NR_MONTYPES)
+		current_par.montype = 4;
+
+	fb_info.monspecs = monspecs[current_par.montype];
+	fb_info.monspecs.dpms = current_par.dpms;
+
+	current_par.currcon	   = -1;
+	current_par.screen_base	   = SCREEN2_BASE;
+	current_par.screen_base_p  = SCREEN_START;
+	current_par.using_vram     = 0;
+
+	/*
+	 * If vram_size is set, we are using VRAM in
+	 * a Risc PC.  However, if the user has specified
+	 * an amount of DRAM then use that instead.
+	 */
+	if (vram_size && !current_par.dram_size) {
+		size = vram_size;
+		current_par.vram_half_sam = vram_size / 1024;
+		current_par.using_vram = 1;
+	} else if (current_par.dram_size)
+		size = current_par.dram_size;
+	else
+		size = (init_var.xres * init_var.yres *
+			init_var.bits_per_pixel) / 8;
+
+	size = PAGE_ALIGN(size);
+
+#ifdef CONFIG_ARCH_RPC
+	if (!current_par.using_vram) {
+		/*
+		 * RiscPC needs to allocate the DRAM memory
+		 * for the framebuffer if we are not using
+		 * VRAM.  Archimedes/A5000 machines use a
+		 * fixed address for their framebuffers.
+		 */
+		current_par.screen_base = (unsigned long)kmalloc(size, GFP_KERNEL);
+		if (current_par.screen_base == 0) {
+			printk(KERN_ERR "acornfb: unable to allocate screen "
+			       "memory\n");
+			return;
+		}
+		current_par.screen_base_p =
+			virt_to_phys(current_par.screen_base);
+	}
+#endif
+#if defined(CONFIG_ARCH_A5K) || defined(CONFIG_ARCH_ARC)
+#define MAX_SIZE	480*1024
+	/*
+	 * Limit maximum screen size.
+	 */
+	if (size > MAX_SIZE)
+		size = MAX_SIZE;
+
+	/*
+	 * Free unused pages
+	 */
+	free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE);
+#endif
+	
+	current_par.screen_size	   = size;
+	current_par.palette_size   = VIDC_PALETTE_SIZE;
+	current_par.allow_modeset  = 1;
+
+	/*
+	 * Lookup the timing for this resolution.  If we can't
+	 * find it, then we can't restore it if we change
+	 * the resolution, so we disable this feature.
+	 */
+	if (acornfb_lookup_timing(&init_var))
+		current_par.allow_modeset = 0;
+
+	/*
+	 * Again, if this does not succeed, then we disallow
+	 * changes to the resolution parameters.
+	 */
+	if (acornfb_set_var(&init_var, -1, &fb_info))
+		current_par.allow_modeset = 0;
+
+	h_sync = 1953125000 / init_var.pixclock;
+	h_sync = h_sync * 512 / (init_var.xres + init_var.left_margin +
+		 init_var.right_margin + init_var.hsync_len);
+	v_sync = h_sync / (init_var.yres + init_var.upper_margin +
+		 init_var.lower_margin + init_var.vsync_len);
+
+	printk("Acornfb: %ldkB %cRAM, %s, using %dx%d, %d.%03dkHz, %dHz\n",
+		current_par.screen_size / 1024,
+		current_par.using_vram ? 'V' : 'D',
+		VIDC_NAME, init_var.xres, init_var.yres,
+		h_sync / 1000, h_sync % 1000, v_sync);
+
+	register_framebuffer(&fb_info);
 }
diff -u --recursive --new-file v2.2.8/linux/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c
--- v2.2.8/linux/drivers/video/cyber2000fb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/cyber2000fb.c	Tue May 11 16:30:36 1999
@@ -0,0 +1,1057 @@
+/*
+ * linux/drivers/video/cyber2000fb.c
+ *
+ * Integraphics Cyber2000 frame buffer device
+ *
+ * Based on cyberfb.c
+ */
+#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/pci.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+
+/*
+ *    Some defaults
+ */
+#define DEFAULT_XRES	640
+#define DEFAULT_YRES	480
+#define DEFAULT_BPP	8
+
+static volatile unsigned char	*CyberRegs;
+
+#include "cyber2000fb.h"
+
+static struct display		global_disp;
+static struct fb_info		fb_info;
+static struct cyber2000fb_par	current_par;
+static struct display_switch	*dispsw;
+static struct fb_var_screeninfo __initdata init_var = {};
+
+#ifdef DEBUG
+static void debug_printf(char *fmt, ...)
+{
+	char buffer[128];
+	va_list ap;
+
+	va_start(ap, fmt);
+	vsprintf(buffer, fmt, ap);
+	va_end(ap);
+
+	printascii(buffer);
+}
+#else
+#define debug_printf(x...) do { } while (0)
+#endif
+
+/*
+ *    Predefined Video Modes
+ */
+static const struct res cyber2000_res[] = {
+	{
+		640, 480,
+		{
+			0x5f, 0x4f, 0x50, 0x80, 0x52, 0x9d, 0x0b, 0x3e,
+			0x00, 0x40,
+			0xe9, 0x8b, 0xdf, 0x50, 0x00, 0xe6, 0x04, 0xc3
+		},
+		0x00,
+		{ 0xd2, 0xce, 0xdb, 0x54 }
+	},
+
+	{
+		800, 600,
+		{
+			0x7f, 0x63, 0x64, 0x00, 0x66, 0x10, 0x6f, 0xf0,
+			0x00, 0x60,
+			0x5b, 0x8f, 0x57, 0x64, 0x00, 0x59, 0x6e, 0xe3
+		},
+		0x00,
+		{ 0x52, 0x85, 0xdb, 0x54 }
+	},
+
+	{
+		1024, 768,
+		{
+			0x9f, 0x7f, 0x80, 0x80, 0x8b, 0x94, 0x1e, 0xfd,
+			0x00, 0x60,
+			0x03, 0x86, 0xff, 0x80, 0x0f, 0x00, 0x1e, 0xe3
+		},
+		0x00,
+		{ 0xd0, 0x52, 0xdb, 0x54 }
+	},
+#if 0
+	{
+		1152, 886,
+		{
+		},
+		{
+		}
+	},
+#endif
+	{
+		1280, 1024,
+		{
+			0xce, 0x9f, 0xa0, 0x8f, 0xa2, 0x1f, 0x28, 0x52,
+			0x00, 0x40,
+			0x08, 0x8f, 0xff, 0xa0, 0x00, 0x03, 0x27, 0xe3
+		},
+		0x1d,
+		{ 0xb4, 0x4b, 0xdb, 0x54 }
+	},
+
+	{
+		1600, 1200,
+		{
+			0xff, 0xc7, 0xc9, 0x9f, 0xcf, 0xa0, 0xfe, 0x10,
+			0x00, 0x40,
+			0xcf, 0x89, 0xaf, 0xc8, 0x00, 0xbc, 0xf1, 0xe3
+		},
+		0x1f,
+		{ 0xbd, 0x10, 0xdb, 0x54 }
+	}
+};
+
+#define NUM_TOTAL_MODES    arraysize(cyber2000_res)
+
+static const char igs_regs[] = {
+	0x10, 0x10,			0x12, 0x00,	0x13, 0x00,
+	0x30, 0x21,	0x31, 0x00,	0x32, 0x00,	0x33, 0x01,
+	0x50, 0x00,	0x51, 0x00,	0x52, 0x00,	0x53, 0x00,
+	0x54, 0x00,	0x55, 0x00,	0x56, 0x00,	0x57, 0x01,
+	0x58, 0x00,	0x59, 0x00,	0x5a, 0x00,
+	0x70, 0x0b,	0x71, 0x10,	0x72, 0x45,	0x73, 0x30,
+	0x74, 0x1b,	0x75, 0x1e,	0x76, 0x00,	0x7a, 0xc8
+};
+
+static const char crtc_idx[] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	0x08, 0x09,
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
+};
+
+static void cyber2000_init_hw(const struct res *res)
+{
+	int i;
+
+	debug_printf("init vga hw for %dx%d\n", res->xres, res->yres);
+
+	cyber2000_outb(0xef, 0x3c2);
+	cyber2000_crtcw(0x0b, 0x11);
+	cyber2000_attrw(0x00, 0x11);
+
+	cyber2000_seqw(0x01, 0x00);
+	cyber2000_seqw(0x01, 0x01);
+	cyber2000_seqw(0x0f, 0x02);
+	cyber2000_seqw(0x00, 0x03);
+	cyber2000_seqw(0x0e, 0x04);
+	cyber2000_seqw(0x03, 0x00);
+
+	for (i = 0; i < sizeof(crtc_idx); i++)
+		cyber2000_crtcw(res->crtc_regs[i], crtc_idx[i]);
+
+	for (i = 0x0a; i < 0x10; i++)
+		cyber2000_crtcw(0, i);
+
+	cyber2000_crtcw(0xff, 0x18);
+
+	cyber2000_grphw(0x00, 0x00);
+	cyber2000_grphw(0x00, 0x01);
+	cyber2000_grphw(0x00, 0x02);
+	cyber2000_grphw(0x00, 0x03);
+	cyber2000_grphw(0x00, 0x04);
+	cyber2000_grphw(0x60, 0x05);
+	cyber2000_grphw(0x05, 0x06);
+	cyber2000_grphw(0x0f, 0x07);
+	cyber2000_grphw(0xff, 0x08);
+
+	for (i = 0; i < 16; i++)
+		cyber2000_attrw(i, i);
+
+	cyber2000_attrw(0x01, 0x10);
+	cyber2000_attrw(0x00, 0x11);
+	cyber2000_attrw(0x0f, 0x12);
+	cyber2000_attrw(0x00, 0x13);
+	cyber2000_attrw(0x00, 0x14);
+
+	for (i = 0; i < sizeof(igs_regs); i += 2)
+		cyber2000_grphw(igs_regs[i+1], igs_regs[i]);
+
+	cyber2000_grphw(res->crtc_ofl, 0x11);
+
+	for (i = 0; i < 4; i += 1)
+		cyber2000_grphw(res->clk_regs[i], 0xb0 + i);
+
+	cyber2000_grphw(0x01, 0x90);
+	cyber2000_grphw(0x80, 0xb9);
+	cyber2000_grphw(0x00, 0xb9);
+
+	cyber2000_outb(0x56, 0x3ce);
+	i = cyber2000_inb(0x3cf);
+	cyber2000_outb(i | 4, 0x3cf);
+	cyber2000_outb(0x04, 0x3c6);
+	cyber2000_outb(i,    0x3cf);
+
+	cyber2000_outb(0x20, 0x3c0);
+	cyber2000_outb(0xff, 0x3c6);
+
+	for (i = 0; i < 256; i++) {
+		cyber2000_outb(i, 0x3c8);
+		cyber2000_outb(0, 0x3c9);
+		cyber2000_outb(0, 0x3c9);
+		cyber2000_outb(0, 0x3c9);
+	}
+}
+
+
+static struct fb_ops cyber2000fb_ops;
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+/*
+ * Hardware Cyber2000 Acceleration
+ */
+static void cyber2000_accel_wait(void)
+{
+	int count = 10000;
+
+	while (cyber2000_inb(0xbf011) & 0x80) {
+		if (!count--) {
+			debug_printf("accel_wait timed out\n");
+			cyber2000_outb(0, 0xbf011);
+			return;
+		}
+		udelay(10);
+	}
+}
+
+static void
+cyber2000_accel_setup(struct display *p)
+{
+	dispsw->setup(p);
+}
+
+static void
+cyber2000_accel_bmove(struct display *p, int sy, int sx, int dy, int dx,
+		int height, int width)
+{
+	unsigned long src, dst, chwidth = p->var.xres_virtual * fontheight(p);
+	int v = 0x8000;
+
+	if (sx < dx) {
+		sx += width - 1;
+		dx += width - 1;
+		v |= 4;
+	}
+
+	if (sy < dy) {
+		sy += height - 1;
+		dy += height - 1;
+		v |= 2;
+	}
+
+	sx *= fontwidth(p);
+	dx *= fontwidth(p);
+	src = sx + sy * chwidth;
+	dst = dx + dy * chwidth;
+	width = width * fontwidth(p) - 1;
+	height = height * fontheight(p) - 1;
+
+	cyber2000_accel_wait();
+	cyber2000_outb(0x00,   0xbf011);
+	cyber2000_outb(0x03,   0xbf048);
+	cyber2000_outw(width,  0xbf060);
+
+	if (p->var.bits_per_pixel != 24) {
+		cyber2000_outl(dst, 0xbf178);
+		cyber2000_outl(src, 0xbf170);
+	} else {
+		cyber2000_outl(dst * 3, 0xbf178);
+		cyber2000_outb(dst, 0xbf078);
+		cyber2000_outl(src * 3, 0xbf170);
+	}
+
+	cyber2000_outw(height, 0xbf062);
+	cyber2000_outw(v,      0xbf07c);
+	cyber2000_outw(0x2800, 0xbf07e);
+}
+
+static void
+cyber2000_accel_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+		int height, int width)
+{
+	unsigned long dst;
+	u32 bgx = attr_bgcol_ec(p, conp);
+
+	dst = sx * fontwidth(p) + sy * p->var.xres_virtual * fontheight(p);
+	width = width * fontwidth(p) - 1;
+	height = height * fontheight(p) - 1;
+
+	cyber2000_accel_wait();
+	cyber2000_outb(0x00,   0xbf011);
+	cyber2000_outb(0x03,   0xbf048);
+	cyber2000_outw(width,  0xbf060);
+	cyber2000_outw(height, 0xbf062);
+
+	switch (p->var.bits_per_pixel) {
+	case 16:
+		bgx = ((u16 *)p->dispsw_data)[bgx];
+	case 8:
+		cyber2000_outl(dst, 0xbf178);
+		break;
+
+	case 24:
+		cyber2000_outl(dst * 3, 0xbf178);
+		cyber2000_outb(dst, 0xbf078);
+		bgx = ((u32 *)p->dispsw_data)[bgx];
+		break;
+	}
+
+	cyber2000_outl(bgx,    0xbf058);
+	cyber2000_outw(0x8000, 0xbf07c);
+	cyber2000_outw(0x0800, 0xbf07e);
+}
+
+static void
+cyber2000_accel_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
+{
+	cyber2000_accel_wait();
+	dispsw->putc(conp, p, c, yy, xx);
+}
+
+static void
+cyber2000_accel_putcs(struct vc_data *conp, struct display *p,
+		const unsigned short *s, int count, int yy, int xx)
+{
+	cyber2000_accel_wait();
+	dispsw->putcs(conp, p, s, count, yy, xx);
+}
+
+static void
+cyber2000_accel_revc(struct display *p, int xx, int yy)
+{
+	cyber2000_accel_wait();
+	dispsw->revc(p, xx, yy);
+}
+
+static void
+cyber2000_accel_clear_margins(struct vc_data *conp, struct display *p, int bottom_only)
+{
+	dispsw->clear_margins(conp, p, bottom_only);
+}
+
+static struct display_switch fbcon_cyber_accel = {
+	cyber2000_accel_setup,
+	cyber2000_accel_bmove,
+	cyber2000_accel_clear,
+	cyber2000_accel_putc,
+	cyber2000_accel_putcs,
+	cyber2000_accel_revc,
+	NULL,
+	NULL,
+	cyber2000_accel_clear_margins,
+	FONTWIDTH(8)|FONTWIDTH(16)
+};
+
+/*
+ * Palette
+ */
+static int
+cyber2000_getcolreg(u_int regno, u_int * red, u_int * green, u_int * blue,
+		    u_int * transp, struct fb_info *fb_info)
+{
+	int t;
+
+	if (regno >= 256)
+		return 1;
+
+	t = current_par.palette[regno].red;
+	*red = t << 10 | t << 4 | t >> 2;
+
+	t = current_par.palette[regno].green;
+	*green = t << 10 | t << 4 | t >> 2;
+
+	t = current_par.palette[regno].blue;
+	*blue = t << 10 | t << 4 | t >> 2;
+
+	*transp = 0;
+
+	return 0;
+}
+
+/*
+ *    Set a single color register. Return != 0 for invalid regno.
+ */
+static int
+cyber2000_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+		    u_int transp, struct fb_info *fb_info)
+{
+	if (regno > 255)
+		return 1;
+
+	red   >>= 10;
+	green >>= 10;
+	blue  >>= 10;
+
+	current_par.palette[regno].red   = red;
+	current_par.palette[regno].green = green;
+	current_par.palette[regno].blue  = blue;
+
+	switch (fb_display[current_par.currcon].var.bits_per_pixel) {
+	case 8:
+		cyber2000_outb(regno, 0x3c8);
+		cyber2000_outb(red,   0x3c9);
+		cyber2000_outb(green, 0x3c9);
+		cyber2000_outb(blue,  0x3c9);
+		break;
+
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		if (regno < 64) {
+			/* write green */
+			cyber2000_outb(regno << 2, 0x3c8);
+			cyber2000_outb(current_par.palette[regno >> 1].red, 0x3c9);
+			cyber2000_outb(green, 0x3c9);
+			cyber2000_outb(current_par.palette[regno >> 1].blue, 0x3c9);
+		}
+
+		if (regno < 32) {
+			/* write red,blue */
+			cyber2000_outb(regno << 3, 0x3c8);
+			cyber2000_outb(red, 0x3c9);
+			cyber2000_outb(current_par.palette[regno << 1].green, 0x3c9);
+			cyber2000_outb(blue, 0x3c9);
+		}
+
+		if (regno < 16)
+			current_par.c_table.cfb16[regno] = regno | regno << 5 | regno << 11;
+		break;
+#endif
+
+#ifdef FBCON_HAS_CFB24
+	case 24:
+		cyber2000_outb(regno, 0x3c8);
+		cyber2000_outb(red,   0x3c9);
+		cyber2000_outb(green, 0x3c9);
+		cyber2000_outb(blue,  0x3c9);
+
+		if (regno < 16)
+			current_par.c_table.cfb24[regno] = regno | regno << 8 | regno << 16;
+		break;
+#endif
+
+	default:
+		return 1;
+	}
+
+	return 0;
+}
+
+static int cyber2000fb_set_timing(struct fb_var_screeninfo *var)
+{
+	int width = var->xres_virtual;
+	int scr_pitch, fetchrow;
+	int i;
+	char b, col;
+
+	switch (var->bits_per_pixel) {
+	case 8:	/* PSEUDOCOLOUR, 256 */
+		b = 0;
+		col = 1;
+		scr_pitch = var->xres_virtual / 8;
+		break;
+
+	case 16:/* DIRECTCOLOUR, 64k */
+		b = 1;
+		col = 2;
+		scr_pitch = var->xres_virtual / 8 * 2;
+		break;
+	case 24:/* TRUECOLOUR, 16m */
+		b = 2;
+		col = 4;
+		scr_pitch = var->xres_virtual / 8 * 3;
+		width *= 3;
+		break;
+
+	default:
+		return 1;
+	}
+
+	for (i = 0; i < NUM_TOTAL_MODES; i++)
+		if (var->xres == cyber2000_res[i].xres &&
+		    var->yres == cyber2000_res[i].yres)
+			break;
+
+	if (i < NUM_TOTAL_MODES)
+		cyber2000_init_hw(cyber2000_res + i);
+
+	fetchrow = scr_pitch + 1;
+
+	debug_printf("Setting regs: pitch=%X, fetchrow=%X, col=%X, b=%X\n",
+		     scr_pitch, fetchrow, col, b);
+
+	cyber2000_outb(0x13, 0x3d4);
+	cyber2000_outb(scr_pitch, 0x3d5);
+	cyber2000_outb(0x14, 0x3ce);
+	cyber2000_outb(fetchrow, 0x3cf);
+	cyber2000_outb(0x15, 0x3ce);
+					/* FIXME: is this the right way round? */
+	cyber2000_outb(((fetchrow >> 4) & 0xf0) | ((scr_pitch >> 8) & 0x0f), 0x3cf);
+	cyber2000_outb(0x77, 0x3ce);
+	cyber2000_outb(col, 0x3cf);
+
+
+	cyber2000_outb(0x33, 0x3ce);
+	cyber2000_outb(0x1c, 0x3cf);
+
+	cyber2000_outw(width - 1, 0xbf018);
+	cyber2000_outw(width - 1, 0xbf218);
+	cyber2000_outb(b, 0xbf01c);
+
+	return 0;
+}
+
+static inline void
+cyber2000fb_update_start(struct fb_var_screeninfo *var)
+{
+#if 0
+	unsigned int base;
+
+	base = var->yoffset * var->xres_virtual + var->xoffset;
+
+	cyber2000_outb(0x0c, 0x3d4);
+	cyber2000_outb(base, 0x3d5);
+	cyber2000_outb(0x0d, 0x3d4);
+	cyber2000_outb(base >> 8, 0x3d5);
+	/* FIXME: need the upper bits of the start offset */
+/*	cyber2000_outb(0x??, 0x3d4);
+	cyber2000_outb(base >> 16, 0x3d5);*/
+#endif
+}
+
+/*
+ *  Open/Release the frame buffer device
+ */
+static int cyber2000fb_open(struct fb_info *info, int user)
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int cyber2000fb_release(struct fb_info *info, int user)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ *    Get the Colormap
+ */
+static int
+cyber2000fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+		     struct fb_info *info)
+{
+	int err = 0;
+
+	if (con == current_par.currcon)	/* current console? */
+		err = fb_get_cmap(cmap, kspc, cyber2000_getcolreg, info);
+	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);
+	return err;
+}
+
+
+/*
+ *    Set the Colormap
+ */
+static int
+cyber2000fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+		     struct fb_info *info)
+{
+	struct display *disp = &fb_display[con];
+	int err = 0;
+
+	if (!disp->cmap.len) {	/* no colormap allocated? */
+		int size;
+
+		if (disp->var.bits_per_pixel == 16)
+			size = 32;
+		else
+			size = 256;
+
+		err = fb_alloc_cmap(&disp->cmap, size, 0);
+	}
+	if (!err) {
+		if (con == current_par.currcon)	/* current console? */
+			err = fb_set_cmap(cmap, kspc, cyber2000_setcolreg,
+					  info);
+		else
+			fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
+	}
+
+	return err;
+}
+
+static int
+cyber2000fb_decode_var(struct fb_var_screeninfo *var, int con, int *visual)
+{
+	switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		*visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		*visual = FB_VISUAL_DIRECTCOLOR;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB24
+	case 24:
+		*visual = FB_VISUAL_TRUECOLOR;
+		break;
+#endif
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ *    Get the Fixed Part of the Display
+ */
+static int
+cyber2000fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+		    struct fb_info *fb_info)
+{
+	struct display *display;
+
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id, "Cyber2000");
+
+	if (con >= 0)
+		display = fb_display + con;
+	else
+		display = &global_disp;
+
+	fix->smem_start	 = (char *)current_par.screen_base_p;
+	fix->smem_len	 = current_par.screen_size;
+	fix->mmio_start	 = (char *)current_par.regs_base_p;
+	fix->mmio_len	 = 0x000c0000;
+	fix->type	 = display->type;
+	fix->type_aux	 = display->type_aux;
+	fix->xpanstep	 = 0;
+	fix->ypanstep	 = display->ypanstep;
+	fix->ywrapstep	 = display->ywrapstep;
+	fix->visual	 = display->visual;
+	fix->line_length = display->line_length;
+	fix->accel	 = 22; /*FB_ACCEL_IGS_CYBER2000*/
+
+	return 0;
+}
+
+
+/*
+ *    Get the User Defined Part of the Display
+ */
+static int
+cyber2000fb_get_var(struct fb_var_screeninfo *var, int con,
+		    struct fb_info *fb_info)
+{
+	if (con == -1)
+		*var = global_disp.var;
+	else
+		*var = fb_display[con].var;
+
+	return 0;
+}
+
+/*
+ *    Set the User Defined Part of the Display
+ */
+static int
+cyber2000fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	struct display *display;
+	int err, chgvar = 0, visual;
+
+	if (con >= 0)
+		display = fb_display + con;
+	else
+		display = &global_disp;
+
+	err = cyber2000fb_decode_var(var, con, &visual);
+	if (err)
+		return err;
+
+	switch (var->activate & FB_ACTIVATE_MASK) {
+	case FB_ACTIVATE_TEST:
+		return 0;
+
+	case FB_ACTIVATE_NXTOPEN:
+	case FB_ACTIVATE_NOW:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (con >= 0) {
+		if (display->var.xres != var->xres)
+			chgvar = 1;
+		if (display->var.yres != var->yres)
+			chgvar = 1;
+		if (display->var.xres_virtual != var->xres_virtual)
+			chgvar = 1;
+		if (display->var.yres_virtual != var->yres_virtual)
+			chgvar = 1;
+		if (display->var.accel_flags != var->accel_flags)
+			chgvar = 1;
+		if (memcmp(&display->var.red, &var->red, sizeof(var->red)))
+			chgvar = 1;
+		if (memcmp(&display->var.green, &var->green, sizeof(var->green)))
+			chgvar = 1;
+		if (memcmp(&display->var.blue, &var->blue, sizeof(var->green)))
+			chgvar = 1;
+	}
+
+	display->var = *var;
+
+	display->screen_base	= (char *)current_par.screen_base;
+	display->visual		= visual;
+	display->type		= FB_TYPE_PACKED_PIXELS;
+	display->type_aux	= 0;
+	display->ypanstep	= 0;
+	display->ywrapstep	= 0;
+	display->line_length	=
+	display->next_line	= (var->xres_virtual * var->bits_per_pixel) / 8;
+	display->can_soft_blank = 1;
+	display->inverse	= 0;
+
+	switch (display->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		dispsw = &fbcon_cfb8;
+		display->dispsw_data = NULL;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		dispsw = &fbcon_cfb16;
+		display->dispsw_data = current_par.c_table.cfb16;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB24
+	case 24:
+		dispsw = &fbcon_cfb24;
+		display->dispsw_data = current_par.c_table.cfb24;
+		break;
+#endif
+	default:
+		printk(KERN_WARNING "cyber2000: no support for %dbpp\n",
+		       display->var.bits_per_pixel);
+		dispsw = &fbcon_dummy;
+		break;
+	}
+
+	if (display->var.accel_flags & FB_ACCELF_TEXT &&
+	    dispsw != &fbcon_dummy)
+		display->dispsw = &fbcon_cyber_accel;
+	else
+		display->dispsw = dispsw;
+
+	if (chgvar && info && info->changevar)
+		info->changevar(con);
+
+	if (con == current_par.currcon) {
+		struct fb_cmap *cmap;
+
+		cyber2000fb_update_start(var);
+		cyber2000fb_set_timing(var);
+
+		if (display->cmap.len)
+			cmap = &display->cmap;
+		else
+			cmap = fb_default_cmap(current_par.palette_size);
+
+		fb_set_cmap(cmap, 1, cyber2000_setcolreg, info);
+	}
+	return 0;
+}
+
+
+/*
+ *    Pan or Wrap the Display
+ */
+static int cyber2000fb_pan_display(struct fb_var_screeninfo *var, int con,
+				   struct fb_info *info)
+{
+	u_int y_bottom;
+
+	y_bottom = var->yoffset;
+
+	if (!(var->vmode & FB_VMODE_YWRAP))
+		y_bottom += var->yres;
+
+	if (var->xoffset > (var->xres_virtual - var->xres))
+		return -EINVAL;
+	if (y_bottom > fb_display[con].var.yres_virtual)
+		return -EINVAL;
+return -EINVAL;
+
+	cyber2000fb_update_start(var);
+
+	fb_display[con].var.xoffset = var->xoffset;
+	fb_display[con].var.yoffset = var->yoffset;
+	if (var->vmode & FB_VMODE_YWRAP)
+		fb_display[con].var.vmode |= FB_VMODE_YWRAP;
+	else
+		fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
+
+	return 0;
+}
+
+
+static int cyber2000fb_ioctl(struct inode *inode, struct file *file,
+		    u_int cmd, u_long arg, int con, struct fb_info *info)
+{
+	return -EINVAL;
+}
+
+
+/*
+ *    Update the `var' structure (called by fbcon.c)
+ *
+ *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
+ *    Since it's called by a kernel driver, no range checking is done.
+ */
+static int
+cyber2000fb_updatevar(int con, struct fb_info *info)
+{
+	if (con == current_par.currcon)
+		cyber2000fb_update_start(&fb_display[con].var);
+	return 0;
+}
+
+static int
+cyber2000fb_switch(int con, struct fb_info *info)
+{
+	struct fb_cmap *cmap;
+
+	if (current_par.currcon >= 0) {
+		cmap = &fb_display[current_par.currcon].cmap;
+
+		if (cmap->len)
+			fb_get_cmap(cmap, 1, cyber2000_getcolreg, info);
+	}
+
+	current_par.currcon = con;
+
+	fb_display[con].var.activate = FB_ACTIVATE_NOW;
+
+	cyber2000fb_set_var(&fb_display[con].var, con, info);
+
+	return 0;
+}
+
+/*
+ *    (Un)Blank the display.
+ */
+static void cyber2000fb_blank(int blank, struct fb_info *fb_info)
+{
+	int i;
+
+	if (blank) {
+		for (i = 0; i < 256; i++) {
+			cyber2000_outb(i, 0x3c8);
+			cyber2000_outb(0, 0x3c9);
+			cyber2000_outb(0, 0x3c9);
+			cyber2000_outb(0, 0x3c9);
+		}
+	} else {
+		for (i = 0; i < 256; i++) {
+			cyber2000_outb(i, 0x3c8);
+			cyber2000_outb(current_par.palette[i].red, 0x3c9);
+			cyber2000_outb(current_par.palette[i].green, 0x3c9);
+			cyber2000_outb(current_par.palette[i].blue, 0x3c9);
+		}
+	}
+}
+
+__initfunc(void cyber2000fb_setup(char *options, int *ints))
+{
+}
+
+static struct fb_ops cyber2000fb_ops =
+{
+	cyber2000fb_open,
+	cyber2000fb_release,
+	cyber2000fb_get_fix,
+	cyber2000fb_get_var,
+	cyber2000fb_set_var,
+	cyber2000fb_get_cmap,
+	cyber2000fb_set_cmap,
+	cyber2000fb_pan_display,
+	cyber2000fb_ioctl
+};
+
+__initfunc(static void
+cyber2000fb_init_fbinfo(void))
+{
+	static int first = 1;
+
+	if (!first)
+		return;
+	first = 0;
+
+	strcpy(fb_info.modename, "Cyber2000");
+	strcpy(fb_info.fontname, "Acorn8x8");
+
+	fb_info.node			= -1;
+	fb_info.fbops			= &cyber2000fb_ops;
+	fb_info.disp			= &global_disp;
+	fb_info.changevar		= NULL;
+	fb_info.switch_con		= cyber2000fb_switch;
+	fb_info.updatevar		= cyber2000fb_updatevar;
+	fb_info.blank			= cyber2000fb_blank;
+	fb_info.flags			= FBINFO_FLAG_DEFAULT;
+
+	/*
+	 * setup initial parameters
+	 */
+	memset(&init_var, 0, sizeof(init_var));
+	init_var.xres_virtual		=
+	init_var.xres			= DEFAULT_XRES;
+	init_var.yres_virtual		=
+	init_var.yres			= DEFAULT_YRES;
+	init_var.bits_per_pixel		= DEFAULT_BPP;
+
+	init_var.red.msb_right		= 0;
+	init_var.green.msb_right	= 0;
+	init_var.blue.msb_right		= 0;
+
+	switch(init_var.bits_per_pixel) {
+	case 8:
+		init_var.bits_per_pixel	= 8;
+		init_var.red.offset	= 0;
+		init_var.red.length	= 8;
+		init_var.green.offset	= 0;
+		init_var.green.length	= 8;
+		init_var.blue.offset	= 0;
+		init_var.blue.length	= 8;
+		break;
+
+	case 16:
+		init_var.bits_per_pixel = 16;
+		init_var.red.offset	= 11;
+		init_var.red.length	= 5;
+		init_var.green.offset	= 5;
+		init_var.green.length	= 6;
+		init_var.blue.offset	= 0;
+		init_var.blue.length	= 5;
+		break;
+
+	case 24:
+		init_var.bits_per_pixel = 24;
+		init_var.red.offset	= 16;
+		init_var.red.length	= 8;
+		init_var.green.offset	= 8;
+		init_var.green.length	= 8;
+		init_var.blue.offset	= 0;
+		init_var.blue.length	= 8;
+		break;
+	}
+
+	init_var.nonstd			= 0;
+	init_var.activate		= FB_ACTIVATE_NOW;
+	init_var.height			= -1;
+	init_var.width			= -1;
+	init_var.accel_flags		= FB_ACCELF_TEXT;
+	init_var.sync			= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT;
+	init_var.vmode			= FB_VMODE_NONINTERLACED;
+}
+
+/*
+ *    Initialization
+ */
+__initfunc(void cyber2000fb_init(void))
+{
+	struct pci_dev *dev;
+	u_int h_sync, v_sync;
+
+	dev = pci_find_device(PCI_VENDOR_ID_INTERG, 0x2000, NULL);
+	if (!dev)
+		return;
+
+	CyberRegs = bus_to_virt(dev->base_address[0]) + 0x00800000;/*FIXME*/
+
+	cyber2000_outb(0x18, 0x46e8);
+	cyber2000_outb(0x01, 0x102);
+	cyber2000_outb(0x08, 0x46e8);
+
+	cyber2000fb_init_fbinfo();
+
+	current_par.currcon		= -1;
+	current_par.screen_base_p	= 0x80000000 + dev->base_address[0];
+	current_par.screen_base		= (u_int)bus_to_virt(dev->base_address[0]);
+	current_par.screen_size		= 0x00200000;
+	current_par.regs_base_p		= 0x80800000 + dev->base_address[0];
+
+	cyber2000fb_set_var(&init_var, -1, &fb_info);
+
+	h_sync = 1953125000 / init_var.pixclock;
+	h_sync = h_sync * 512 / (init_var.xres + init_var.left_margin +
+		 init_var.right_margin + init_var.hsync_len);
+	v_sync = h_sync / (init_var.yres + init_var.upper_margin +
+		 init_var.lower_margin + init_var.vsync_len);
+
+	printk("Cyber2000: %ldkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+		current_par.screen_size >> 10,
+		init_var.xres, init_var.yres,
+		h_sync / 1000, h_sync % 1000, v_sync);
+
+	if (register_framebuffer(&fb_info) < 0)
+		return;
+
+	MOD_INC_USE_COUNT;	/* TODO: This driver cannot be unloaded yet */
+}
+
+
+
+#ifdef MODULE
+int init_module(void)
+{
+	cyber2000fb_init();
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	/* Not reached because the usecount will never be
+	   decremented to zero */
+	unregister_framebuffer(&fb_info);
+	/* TODO: clean up ... */
+}
+
+#endif				/* MODULE */
diff -u --recursive --new-file v2.2.8/linux/drivers/video/cyber2000fb.h linux/drivers/video/cyber2000fb.h
--- v2.2.8/linux/drivers/video/cyber2000fb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/cyber2000fb.h	Tue May 11 16:30:36 1999
@@ -0,0 +1,78 @@
+/*
+ * linux/drivers/video/cyber2000fb.h
+ *
+ * Integraphics Cyber2000 frame buffer device
+ */
+
+#define arraysize(x)    (sizeof(x)/sizeof(*(x)))
+#define cyber2000_outb(dat,reg)	(CyberRegs[reg] = dat)
+#define cyber2000_outw(dat,reg)	(*(unsigned short *)&CyberRegs[reg] = dat)
+#define cyber2000_outl(dat,reg)	(*(unsigned long *)&CyberRegs[reg] = dat)
+
+#define cyber2000_inb(reg)	(CyberRegs[reg])
+#define cyber2000_inw(reg)	(*(unsigned short *)&CyberRegs[reg])
+#define cyber2000_inl(reg)	(*(unsigned long *)&CyberRegs[reg])
+
+static inline void cyber2000_crtcw(int val, int reg)
+{
+	cyber2000_outb(reg, 0x3d4);
+	cyber2000_outb(val, 0x3d5);
+}
+
+static inline void cyber2000_grphw(int val, int reg)
+{
+	cyber2000_outb(reg, 0x3ce);
+	cyber2000_outb(val, 0x3cf);
+}
+
+static inline void cyber2000_attrw(int val, int reg)
+{
+	cyber2000_inb(0x3da);
+	cyber2000_outb(reg, 0x3c0);
+	cyber2000_inb(0x3c1);
+	cyber2000_outb(val, 0x3c0);
+}
+
+static inline void cyber2000_seqw(int val, int reg)
+{
+	cyber2000_outb(reg, 0x3c4);
+	cyber2000_outb(val, 0x3c5);
+}
+
+struct cyber2000fb_par {
+	unsigned long	screen_base;
+	unsigned long	screen_base_p;
+	unsigned long	regs_base;
+	unsigned long	regs_base_p;
+	unsigned long	screen_end;
+	unsigned long	screen_size;
+	unsigned int	palette_size;
+	  signed int	currcon;
+	/*
+	 * palette
+	 */
+	struct {
+		u8			red;
+		u8			green;
+		u8			blue;
+	} palette[256];
+	/*
+	 * colour mapping table
+	 */
+	union {
+#ifdef FBCON_HAS_CFB16
+		u16			cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB24
+		u32			cfb24[16];
+#endif
+	} c_table;
+};
+
+struct res {
+	int	xres;
+	int	yres;
+	unsigned char crtc_regs[18];
+	unsigned char crtc_ofl;
+	unsigned char clk_regs[4];
+};
diff -u --recursive --new-file v2.2.8/linux/drivers/video/dummycon.c linux/drivers/video/dummycon.c
--- v2.2.8/linux/drivers/video/dummycon.c	Mon Aug  3 12:45:46 1998
+++ linux/drivers/video/dummycon.c	Tue May 11 16:30:36 1999
@@ -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,7 +17,7 @@
  *  Dummy console driver
  */
 
-#if defined(CONFIG_ARM)
+#if defined(__arm__)
 #define DUMMY_COLUMNS	ORIG_VIDEO_COLS
 #define DUMMY_ROWS	ORIG_VIDEO_LINES
 #else
diff -u --recursive --new-file v2.2.8/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.2.8/linux/drivers/video/fbmem.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/video/fbmem.c	Tue May 11 16:30:36 1999
@@ -44,7 +44,7 @@
      *  Frame buffer device initialization and setup routines
      */
 
-extern unsigned long acornfb_init(void);
+extern void acornfb_init(void);
 extern void acornfb_setup(char *options, int *ints);
 extern void amifb_init(void);
 extern void amifb_setup(char *options, int *ints);
@@ -56,6 +56,8 @@
 extern void cyberfb_setup(char *options, int *ints);
 extern void pm2fb_init(void);
 extern void pm2fb_setup(char *options, int *ints);
+extern void cyber2000fb_init(void);
+extern void cyber2000fb_setup(char *options, int *ints);
 extern void retz3fb_init(void);
 extern void retz3fb_setup(char *options, int *ints);
 extern void clgenfb_init(void);
@@ -120,6 +122,9 @@
 #ifdef CONFIG_FB_CYBER
 	{ "cyber", cyberfb_init, cyberfb_setup },
 #endif
+#ifdef CONFIG_FB_CYBER2000
+	{ "cyber2000", cyber2000fb_init, cyber2000fb_setup },
+#endif
 #ifdef CONFIG_FB_PM2
 	{ "pm2fb", pm2fb_init, pm2fb_setup },
 #endif
@@ -501,6 +506,13 @@
 #elif defined(__mips__)
 	pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
 	pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
+#elif defined(__arm__)
+#if defined(CONFIG_CPU_32) && !defined(CONFIG_ARCH_ACORN)
+	/* On Acorn architectures, we want to keep the framebuffer
+	 * cached.
+	 */
+	pgprot_val(vma->vm_page_prot) &= ~(PTE_CACHEABLE | PTE_BUFFERABLE);
+#endif
 #else
 #warning What do we have to do here??
 #endif
diff -u --recursive --new-file v2.2.8/linux/drivers/video/vgacon.c linux/drivers/video/vgacon.c
--- v2.2.8/linux/drivers/video/vgacon.c	Mon Sep 28 10:51:34 1998
+++ linux/drivers/video/vgacon.c	Tue May 11 16:30:36 1999
@@ -153,7 +153,7 @@
 __initfunc(static const char *vgacon_startup(void))
 {
 	const char *display_desc = NULL;
-	u16 saved;
+	u16 saved1, saved2;
 	u16 *p;
 
 	if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) {
@@ -267,18 +267,24 @@
 	 *	Are there smarter methods around?
 	 */
 	p = (u16 *)vga_vram_base;
-	saved = scr_readw(p);
+	saved1 = scr_readw(p);
+	saved2 = scr_readw(p + 1);
 	scr_writew(0xAA55, p);
-	if (scr_readw(p) != 0xAA55) {
-		scr_writew(saved, p);
+	scr_writew(0x55AA, p + 1);
+	if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
+		scr_writew(saved1, p);
+		scr_writew(saved2, p + 1);
 		goto no_vga;
 	}
 	scr_writew(0x55AA, p);
-	if (scr_readw(p) != 0x55AA) {
-		scr_writew(saved, p);
+	scr_writew(0xAA55, p + 1);
+	if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
+		scr_writew(saved1, p);
+		scr_writew(saved2, p + 1);
 		goto no_vga;
 	}
-	scr_writew(saved, p);
+	scr_writew(saved1, p);
+	scr_writew(saved2, p + 1);
 
 	if (vga_video_type == VIDEO_TYPE_EGAC
 	    || vga_video_type == VIDEO_TYPE_VGAC
diff -u --recursive --new-file v2.2.8/linux/fs/adfs/dir.c linux/fs/adfs/dir.c
--- v2.2.8/linux/fs/adfs/dir.c	Wed Apr 28 11:37:30 1999
+++ linux/fs/adfs/dir.c	Tue May 11 16:30:36 1999
@@ -76,13 +76,34 @@
 	return val;
 }
 
+static unsigned int adfs_filetype (unsigned int load)
+{
+	if ((load & 0xfff00000) != 0xfff00000)
+		return (unsigned int) -1;
+	return (load >> 8) & 0xfff;
+}
+
 static unsigned int adfs_time (unsigned int load, unsigned int exec)
 {
 	unsigned int high, low;
 
-	high = ((load << 24) | (exec >> 8)) - 0x336e996a;
+	/* Check for unstamped files.  */
+	if ((load & 0xfff00000) != 0xfff00000)
+		return 0;
+
+	high = ((load << 24) | (exec >> 8));
 	low  =  exec & 255;
 
+	/* Files dated pre 1970.  */
+	if (high < 0x336e996a)
+		return 0;
+
+	high -= 0x336e996a;
+
+	/* Files dated post 2038 ish.  */
+	if (high > 0x31ffffff)
+		return 0x7fffffff;
+
 	/* 65537 = h256,l1
 	 * (h256 % 100) = 56         h256 / 100 = 2
 	 *    56 << 8 = 14336           2 * 256 = 512
@@ -204,6 +225,18 @@
 		brelse (bhp[i]);
 }
 
+/* convert a disk-based directory entry to a Linux ADFS directory entry */
+static inline void
+adfs_dirent_to_idirent(struct adfs_idir_entry *ide, struct adfs_direntry *de)
+{
+	ide->name_len =	adfs_readname(ide->name, de->dirobname, ADFS_NAME_LEN);
+	ide->file_id  = adfs_val(de->dirinddiscadd, 3);
+	ide->size     = adfs_val(de->dirlen, 4);
+	ide->mode     = de->newdiratts;
+	ide->mtime    = adfs_time(adfs_val(de->dirload, 4), adfs_val(de->direxec, 4));
+	ide->filetype = adfs_filetype(adfs_val(de->dirload, 4));
+}
+
 int adfs_dir_get (struct super_block *sb, struct buffer_head **bhp,
 		  int buffers, int pos, unsigned long parent_object_id,
 		  struct adfs_idir_entry *ide)
@@ -228,13 +261,8 @@
 	if (!de.dirobname[0])
 		return 0;
 
-	ide->name_len =	adfs_readname (ide->name, de.dirobname, ADFS_NAME_LEN);
 	ide->inode_no = adfs_inode_generate (parent_object_id, pos);
-	ide->file_id  = adfs_val (de.dirinddiscadd, 3);
-	ide->size     = adfs_val (de.dirlen, 4);
-	ide->mode     = de.newdiratts;
-	ide->mtime    = adfs_time (adfs_val (de.dirload, 4), adfs_val (de.direxec, 4));
-	ide->filetype = (adfs_val (de.dirload, 4) >> 8) & 0xfff;
+	adfs_dirent_to_idirent(ide, &de);
 	return 1;
 }
 
@@ -262,12 +290,7 @@
 	if (!de.dirobname[0])
 		return 0;
 
-	ide->name_len =	adfs_readname (ide->name, de.dirobname, ADFS_NAME_LEN);
-	ide->size     = adfs_val (de.dirlen, 4);
-	ide->mode     = de.newdiratts;
-	ide->file_id  = adfs_val (de.dirinddiscadd, 3);
-	ide->mtime    = adfs_time (adfs_val (de.dirload, 4), adfs_val (de.direxec, 4));
-	ide->filetype = (adfs_val (de.dirload, 4) >> 8) & 0xfff;
+	adfs_dirent_to_idirent(ide, &de);
 	return 1;
 }	
 
diff -u --recursive --new-file v2.2.8/linux/fs/buffer.c linux/fs/buffer.c
--- v2.2.8/linux/fs/buffer.c	Tue May 11 13:10:30 1999
+++ linux/fs/buffer.c	Thu May 13 13:14:04 1999
@@ -100,8 +100,7 @@
 				each time we call refill */
 		int nref_dirt; /* Dirty buffer threshold for activating bdflush
 				  when trying to refill buffers. */
-		int interval;  /* Interval (seconds) between spontaneous
-				  bdflush runs */
+		int dummy1;    /* unused */
 		int age_buffer;  /* Time for normal buffer to age before 
 				    we flush it */
 		int age_super;  /* Time for superblock to age before we 
@@ -110,10 +109,10 @@
 		int dummy3;    /* unused */
 	} b_un;
 	unsigned int data[N_PARAM];
-} bdf_prm = {{40, 500, 64, 256, 5, 30*HZ, 5*HZ, 1884, 2}};
+} bdf_prm = {{40, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
 
 /* These are the min and max parameter values that we will allow to be assigned */
-int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  1,   1*HZ,   1*HZ, 1, 1};
+int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   1*HZ,   1*HZ, 1, 1};
 int bdflush_max[N_PARAM] = {100,5000, 2000, 2000,100, 600*HZ, 600*HZ, 2047, 5};
 
 void wakeup_bdflush(int);
@@ -1554,6 +1553,7 @@
  * response to dirty buffers.  Once this process is activated, we write back
  * a limited number of buffers to the disks and then go back to sleep again.
  */
+static struct wait_queue * bdflush_wait = NULL;
 static struct wait_queue * bdflush_done = NULL;
 struct task_struct *bdflush_tsk = 0;
 
@@ -1561,7 +1561,7 @@
 {
 	if (current == bdflush_tsk)
 		return;
-	wake_up_process(bdflush_tsk);
+	wake_up(&bdflush_wait);
 	if (wait) {
 		run_task_queue(&tq_disk);
 		sleep_on(&bdflush_done);
@@ -1570,107 +1570,82 @@
 
 
 /* 
- * Here we attempt to write back old buffers.
- * To prevent deadlocks for a loop device:
- * 1) Do non-blocking writes to loop (avoids deadlock with running
- *	out of request blocks).
- * 2) But do a blocking write if the only dirty buffers are loop buffers
- *	(otherwise we go into an infinite busy-loop).
- * 3) Quit writing loop blocks if a freelist went low (avoids deadlock
- *	with running out of free buffers for loop's "real" device).
-*/
+ * Here we attempt to write back old buffers.  We also try to flush inodes 
+ * and supers as well, since this function is essentially "update", and 
+ * otherwise there would be no way of ensuring that these quantities ever 
+ * get written back.  Ideally, we would have a timestamp on the inodes
+ * and superblocks so that we could write back only the old ones as well
+ */
 
-static inline void sync_old_buffers(void)
+static int sync_old_buffers(void)
 {
 	int i;
-	int ndirty = 0;
-	int wrta_cmd = WRITEA;
-#ifdef DEBUG
-	int ncount = 0, nwritten = 0;
-#endif
+	int ndirty, nwritten;
+	int nlist;
+	int ncount;
 	struct buffer_head * bh, *next;
 
-#ifdef DEBUG
-	bh = lru_list[BUF_CLEAN];
-	if(bh)
-		for(i = nr_buffers_type[BUF_CLEAN]; --i > 0; bh = next) {
-			next = bh->b_next_free;
+	sync_supers(0);
+	sync_inodes(0);
 
-			/* Dirty/locked buffer on clean list?  Refile it */
-			if (buffer_locked(bh) || buffer_dirty(bh)) {
-				ncount++;
-				refile_buffer(bh);
-			}
-		}
+	ncount = 0;
+#ifdef DEBUG
+	for(nlist = 0; nlist < NR_LIST; nlist++)
+#else
+	for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++)
 #endif
+	{
+		ndirty = 0;
+		nwritten = 0;
+	repeat:
 
-	bh = lru_list[BUF_LOCKED];
-	if(bh)
-		for(i = nr_buffers_type[BUF_LOCKED]; --i > 0; bh = next) {
-			next = bh->b_next_free;
-
-			/* Unlocked buffer on locked list?  Refile it */
-			if (!buffer_locked(bh))
-				refile_buffer(bh);
-		}
-
- restart:
-	bh = lru_list[BUF_DIRTY];
-	if(bh) 
-		for (i = nr_buffers_type[BUF_DIRTY];
-		     i-- > 0 && ndirty < bdf_prm.b_un.ndirty; 
-		     bh = next) {
-			/* We may have stalled while waiting for
-			   I/O to complete. */
-			if(bh->b_list != BUF_DIRTY)
-				goto restart;
-			next = bh->b_next_free;
-			if(!lru_list[BUF_DIRTY]) {
-				printk("Dirty list empty %d\n", i);
-				break;
-			}
-					  
-			/* Clean buffer on dirty list?  Refile it */
-			if (!buffer_dirty(bh)) {
-				refile_buffer(bh);
-				continue;
-			}
-					  
-			if (buffer_locked(bh))
-				continue;
-			/* Should we write back buffers that are
-			   shared or not??  Currently dirty buffers
-			   are not shared, so it does not matter */
-			next->b_count++;
-			bh->b_count++;
-			ndirty++;
-			bh->b_flushtime = 0;
-			if (MAJOR(bh->b_dev) == LOOP_MAJOR) {
-				ll_rw_block(wrta_cmd,1, &bh);
-				wrta_cmd = WRITEA;
-				if (buffer_dirty(bh))
-					--ndirty;
-			}
-			else
-				ll_rw_block(WRITE, 1, &bh);
-			bh->b_count--;
-			next->b_count--;
-		}
-	/* If we didn't write anything, but there are still
-	 * dirty buffers, then make the next write to a
-	 * loop device to be a blocking write.
-	 * This lets us block--which we _must_ do! */
-	if (ndirty == 0
-	    && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) {
-		wrta_cmd = WRITE;
-		goto restart;
+		bh = lru_list[nlist];
+		if(bh) 
+			 for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) {
+				 /* We may have stalled while waiting for I/O to complete. */
+				 if(bh->b_list != nlist) goto repeat;
+				 next = bh->b_next_free;
+				 if(!lru_list[nlist]) {
+					 printk("Dirty list empty %d\n", i);
+					 break;
+				 }
+				 
+				 /* Clean buffer on dirty list?  Refile it */
+				 if (nlist == BUF_DIRTY && !buffer_dirty(bh) && !buffer_locked(bh)) {
+					 refile_buffer(bh);
+					 continue;
+				 }
+				  
+				  /* Unlocked buffer on locked list?  Refile it */
+				  if (nlist == BUF_LOCKED && !buffer_locked(bh)) {
+					  refile_buffer(bh);
+					  continue;
+				  }
+				 
+				 if (buffer_locked(bh) || !buffer_dirty(bh))
+					  continue;
+				 ndirty++;
+				 if(time_before(jiffies, bh->b_flushtime))
+					continue;
+				 nwritten++;
+				 next->b_count++;
+				 bh->b_count++;
+				 bh->b_flushtime = 0;
+#ifdef DEBUG
+				 if(nlist != BUF_DIRTY) ncount++;
+#endif
+				 ll_rw_block(WRITE, 1, &bh);
+				 bh->b_count--;
+				 next->b_count--;
+			 }
 	}
-
+	run_task_queue(&tq_disk);
 #ifdef DEBUG
 	if (ncount) printk("sync_old_buffers: %d dirty buffers not on dirty list\n", ncount);
-	printk("wrote %d/%d buffers...", nwritten, ndirty);
+	printk("Wrote %d/%d buffers\n", nwritten, ndirty);
 #endif
 	run_task_queue(&tq_disk);
+	return 0;
 }
 
 
@@ -1687,12 +1662,10 @@
 	if (!capable(CAP_SYS_ADMIN))
 		goto out;
 
-	if (func == 1)
-		/* Func 1 used to call sync_old_buffers; a user space
-		   daemon would call it periodically.  This is no
-		   longer necessary.  Returning -EPERM here makes the
-		   daemon silently exit.  */
-		goto out;
+	if (func == 1) {
+		 error = sync_old_buffers();
+		 goto out;
+	}
 
 	/* Basically func 1 means read param 1, 2 means write param 1, etc */
 	if (func >= 2) {
@@ -1721,17 +1694,27 @@
 	return error;
 }
 
-/* This is the actual bdflush daemon itself. It used to be started
- * from the syscall above, but now we launch it ourselves internally
- * with kernel_thread(...)  directly after the first thread in
- * init/main.c.  Every so often, or when woken up by another task that
- * needs memory, we call sync_old_buffers to partially clear the dirty list.
- */
+/* This is the actual bdflush daemon itself. It used to be started from
+ * the syscall above, but now we launch it ourselves internally with
+ * kernel_thread(...)  directly after the first thread in init/main.c */
 
+/* To prevent deadlocks for a loop device:
+ * 1) Do non-blocking writes to loop (avoids deadlock with running
+ *	out of request blocks).
+ * 2) But do a blocking write if the only dirty buffers are loop buffers
+ *	(otherwise we go into an infinite busy-loop).
+ * 3) Quit writing loop blocks if a freelist went low (avoids deadlock
+ *	with running out of free buffers for loop's "real" device).
+*/
 int bdflush(void * unused) 
 {
-	long remaining = HZ * bdf_prm.b_un.interval;
-	struct task_struct *tsk = current;
+	int i;
+	int ndirty;
+	int nlist;
+	int ncount;
+	struct buffer_head * bh, *next;
+	int major;
+	int wrta_cmd = WRITEA;	/* non-blocking write for LOOP */
 
 	/*
 	 *	We have a bare-bones task_struct, and really should fill
@@ -1739,12 +1722,10 @@
 	 *	display semi-sane things. Not real crucial though...  
 	 */
 
-	tsk->session = 1;
-	tsk->pgrp = 1;
-	tsk->dumpable = 0;  /* inhibit ptrace() */
-	strcpy(tsk->comm, "kflushd");
-	sigfillset(&tsk->blocked);
-	bdflush_tsk = tsk;
+	current->session = 1;
+	current->pgrp = 1;
+	sprintf(current->comm, "kflushd");
+	bdflush_tsk = current;
 
 	/*
 	 *	As a kernel thread we want to tamper with system buffers
@@ -1754,36 +1735,93 @@
 	lock_kernel();
 		 
 	for (;;) {
-		tsk->state = TASK_INTERRUPTIBLE;
-		remaining = schedule_timeout(remaining);
-
 #ifdef DEBUG
 		printk("bdflush() activated...");
 #endif
-		CHECK_EMERGENCY_SYNC
 
-		if (remaining == 0) {
-			/*
-			 * Also try to flush inodes and supers, since
-			 * otherwise there would be no way of ensuring
-			 * that these quantities ever get written
-			 * back.  Ideally, we would have a timestamp
-			 * on the inodes and superblocks so that we
-			 * could write back only the old ones.
-			 */
-			sync_supers(0);
-			sync_inodes(0);
-			remaining = HZ * bdf_prm.b_un.interval;
-		}
-			
-		/* Keep flushing till there aren't very many dirty buffers */
-		do {
-			sync_old_buffers();
-		} while(nr_buffers_type[BUF_DIRTY] > nr_buffers * bdf_prm.b_un.nfract/100);
+		CHECK_EMERGENCY_SYNC
 
-		wake_up(&bdflush_done);
+		ncount = 0;
 #ifdef DEBUG
+		for(nlist = 0; nlist < NR_LIST; nlist++)
+#else
+		for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++)
+#endif
+		 {
+			 ndirty = 0;
+		 repeat:
+
+			 bh = lru_list[nlist];
+			 if(bh) 
+				  for (i = nr_buffers_type[nlist]; i-- > 0 && ndirty < bdf_prm.b_un.ndirty; 
+				       bh = next) {
+					  /* We may have stalled while waiting for I/O to complete. */
+					  if(bh->b_list != nlist) goto repeat;
+					  next = bh->b_next_free;
+					  if(!lru_list[nlist]) {
+						  printk("Dirty list empty %d\n", i);
+						  break;
+					  }
+					  
+					  /* Clean buffer on dirty list?  Refile it */
+					  if (nlist == BUF_DIRTY && !buffer_dirty(bh)) {
+						  refile_buffer(bh);
+						  continue;
+					  }
+					  
+					  /* Unlocked buffer on locked list?  Refile it */
+					  if (nlist == BUF_LOCKED && !buffer_locked(bh)) {
+						  refile_buffer(bh);
+						  continue;
+					  }
+					  
+					  if (buffer_locked(bh) || !buffer_dirty(bh))
+						   continue;
+					  major = MAJOR(bh->b_dev);
+					  /* Should we write back buffers that are shared or not??
+					     currently dirty buffers are not shared, so it does not matter */
+					  next->b_count++;
+					  bh->b_count++;
+					  ndirty++;
+					  bh->b_flushtime = 0;
+					  if (major == LOOP_MAJOR) {
+						  ll_rw_block(wrta_cmd,1, &bh);
+						  wrta_cmd = WRITEA;
+						  if (buffer_dirty(bh))
+							  --ndirty;
+					  }
+					  else
+					  ll_rw_block(WRITE, 1, &bh);
+#ifdef DEBUG
+					  if(nlist != BUF_DIRTY) ncount++;
+#endif
+					  bh->b_count--;
+					  next->b_count--;
+				  }
+		 }
+#ifdef DEBUG
+		if (ncount) printk("sys_bdflush: %d dirty buffers not on dirty list\n", ncount);
 		printk("sleeping again.\n");
 #endif
+		/* If we didn't write anything, but there are still
+		 * dirty buffers, then make the next write to a
+		 * loop device to be a blocking write.
+		 * This lets us block--which we _must_ do! */
+		if (ndirty == 0 && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) {
+			wrta_cmd = WRITE;
+			continue;
+		}
+		run_task_queue(&tq_disk);
+		wake_up(&bdflush_done);
+		
+		/* If there are still a lot of dirty buffers around, skip the sleep
+		   and flush some more */
+		if(ndirty == 0 || nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) {
+			spin_lock_irq(&current->sigmask_lock);
+			flush_signals(current);
+			spin_unlock_irq(&current->sigmask_lock);
+
+			interruptible_sleep_on(&bdflush_wait);
+		}
 	}
 }
diff -u --recursive --new-file v2.2.8/linux/fs/hfs/ChangeLog linux/fs/hfs/ChangeLog
--- v2.2.8/linux/fs/hfs/ChangeLog	Tue Feb 23 15:21:34 1999
+++ linux/fs/hfs/ChangeLog	Wed May 12 13:26:34 1999
@@ -1,3 +1,19 @@
+1999-04-12  a sun  <asun@hecate.darksunrising.blah>
+
+	* file_hdr.c (hdr_read): added rootinfo behaviour for DID header.
+
+1999-04-11  a sun  <asun@hecate.darksunrising.blah>
+
+	* super.c (parse_options): added s_version so that we can select
+	between different versions of the same layout.
+
+1999-04-05  a sun  <asun@hecate.darksunrising.blah>
+
+	* linux/hfs_fs.h: unified netatalk and appledouble header format. 
+	added in all of the AFP attribute bits.
+
+	* file_hdr.c: added netatalk appledouble v2 compatible headers. 
+
 1999-01-30  a sun  <asun@hecate.darksunrising.blah>
 
 	* catalog.c (hfs_cat_move): fixed corruption problem with
diff -u --recursive --new-file v2.2.8/linux/fs/hfs/file_hdr.c linux/fs/hfs/file_hdr.c
--- v2.2.8/linux/fs/hfs/file_hdr.c	Tue Feb 23 15:21:34 1999
+++ linux/fs/hfs/file_hdr.c	Wed May 12 13:26:34 1999
@@ -30,6 +30,14 @@
 #include <linux/hfs_fs_i.h>
 #include <linux/hfs_fs.h>
 
+/* prodos types */
+#define PRODOSI_FTYPE_DIR   0x0F
+#define PRODOSI_FTYPE_TEXT  0x04
+#define PRODOSI_FTYPE_8BIT  0xFF
+#define PRODOSI_FTYPE_16BIT 0xB3
+
+#define PRODOSI_AUXTYPE_DIR 0x0200
+
 /*================ Forward declarations ================*/
 
 static hfs_rwret_t hdr_read(struct file *, char *, hfs_rwarg_t, loff_t *);
@@ -84,13 +92,14 @@
 const struct hfs_hdr_layout hfs_dbl_fil_hdr_layout = {
 	__constant_htonl(HFS_DBL_MAGIC),	/* magic   */
 	__constant_htonl(HFS_HDR_VERSION_2),	/* version */
-	5,					/* entries */
+	6,					/* entries */
 	{					/* descr[] */
+		{HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
 		{HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16},
 		{HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
-		{HFS_HDR_MACI,  offsetof(struct hfs_dbl_hdr, fileinfo),    4},
-		{HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
-		{HFS_HDR_RSRC,  HFS_DBL_HDR_LEN,                           ~0},
+		{HFS_HDR_MACI,  offsetof(struct hfs_dbl_hdr, fileinfo),     4},
+		{HFS_HDR_DID,   offsetof(struct hfs_dbl_hdr, cnid),         4},
+		{HFS_HDR_RSRC,  HFS_DBL_HDR_LEN,                           ~0}
 	},
 	{					/* order[] */
 		(struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[0],
@@ -98,24 +107,55 @@
 		(struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[2],
 		(struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[3],
 		(struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[4],
+		(struct hfs_hdr_descr *)&hfs_dbl_fil_hdr_layout.descr[5]
 	}
 };
 
 const struct hfs_hdr_layout hfs_dbl_dir_hdr_layout = {
 	__constant_htonl(HFS_DBL_MAGIC),	/* magic   */
 	__constant_htonl(HFS_HDR_VERSION_2),	/* version */
-	4,					/* entries */
+	5,					/* entries */
 	{					/* descr[] */
+		{HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
 		{HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16},
 		{HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
-		{HFS_HDR_MACI,  offsetof(struct hfs_dbl_hdr, fileinfo),    4},
-		{HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
+		{HFS_HDR_MACI,  offsetof(struct hfs_dbl_hdr, fileinfo),     4},
+		{HFS_HDR_DID,   offsetof(struct hfs_dbl_hdr, cnid),         4}
 	},
 	{					/* order[] */
 		(struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[0],
 		(struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[1],
 		(struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[2],
 		(struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[3],
+		(struct hfs_hdr_descr *)&hfs_dbl_dir_hdr_layout.descr[4]
+	}
+};
+
+const struct hfs_hdr_layout hfs_nat2_hdr_layout = {
+	__constant_htonl(HFS_DBL_MAGIC),	/* magic   */
+	__constant_htonl(HFS_HDR_VERSION_2),	/* version */
+	9,					/* entries */
+	{					/* descr[] */
+		{HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
+		{HFS_HDR_COMNT, offsetof(struct hfs_dbl_hdr, comment),      0},
+		{HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16},
+		{HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
+		{HFS_HDR_AFPI,  offsetof(struct hfs_dbl_hdr, fileinfo),     4},
+		{HFS_HDR_DID,   offsetof(struct hfs_dbl_hdr, cnid),         4},
+		{HFS_HDR_SNAME,  offsetof(struct hfs_dbl_hdr, short_name), ~0},
+		{HFS_HDR_PRODOSI,  offsetof(struct hfs_dbl_hdr, prodosi),   8},
+		{HFS_HDR_RSRC,  HFS_NAT_HDR_LEN,                           ~0}
+	},
+	{					/* order[] */
+		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[0],
+		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[1],
+		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[2],
+		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[3],
+		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[4],
+		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[5],
+		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[6],
+		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[7],
+		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[8]
 	}
 };
 
@@ -124,18 +164,18 @@
 	__constant_htonl(HFS_HDR_VERSION_1),	/* version */
 	5,					/* entries */
 	{					/* descr[] */
+		{HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
+		{HFS_HDR_COMNT, offsetof(struct hfs_dbl_hdr, comment),      0},
+		{HFS_HDR_OLDI,  offsetof(struct hfs_dbl_hdr, create_time), 16},
+		{HFS_HDR_FINFO, offsetof(struct hfs_dbl_hdr, finderinfo),  32},
 		{HFS_HDR_RSRC,  HFS_NAT_HDR_LEN,                           ~0},
-		{HFS_HDR_FNAME, offsetof(struct hfs_nat_hdr, real_name),   ~0},
-		{HFS_HDR_COMNT, offsetof(struct hfs_nat_hdr, comment),     0},
-		{HFS_HDR_OLDI,  offsetof(struct hfs_nat_hdr, create_time), 16},
-		{HFS_HDR_FINFO, offsetof(struct hfs_nat_hdr, finderinfo),  32},
 	},
 	{					/* order[] */
+		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[0],
 		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[1],
 		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[2],
 		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[3],
-		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[4],
-		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[0],
+		(struct hfs_hdr_descr *)&hfs_nat_hdr_layout.descr[4]
 	}
 };
 
@@ -187,6 +227,7 @@
 			length = entry->key.CName.Len;
 			break;
 
+		case HFS_HDR_SNAME:
 		default:
 			length = 0;
 		}
@@ -456,6 +497,8 @@
 		case HFS_HDR_DATES:
 			get_dates(entry, inode, (hfs_u32 *)tmp);
 			if (descr->id == HFS_HDR_DATES) {
+				/* XXX: access date. hfsplus actually
+                                   has this. */
 				memcpy(tmp + 12, tmp + 4, 4);
 			} else if ((entry->type == HFS_CDR_FIL) &&
 				   (entry->u.file.flags & HFS_FIL_LOCK)) {
@@ -472,6 +515,31 @@
 			limit = 32;
 			break;
 
+		case HFS_HDR_AFPI:
+			/* XXX: this needs to do more mac->afp mappings */
+			hfs_put_ns(0, tmp);
+			if ((entry->type == HFS_CDR_FIL) &&
+			    (entry->u.file.flags & HFS_FIL_LOCK)) {
+				hfs_put_hs(HFS_AFP_RDONLY, tmp + 2);
+			} else {
+				hfs_put_ns(0, tmp + 2);
+			}
+			p = tmp;
+			limit = 4;
+		        break;
+
+		case HFS_HDR_PRODOSI:
+			/* XXX: this needs to do mac->prodos translations */
+			memset(tmp, 0, 8);
+#if 0
+			hfs_put_ns(0, tmp); /* access */
+			hfs_put_ns(0, tmp); /* type */
+			hfs_put_nl(0, tmp); /* aux type */
+#endif
+			p = tmp;
+			limit = 8;
+		        break;
+
 		case HFS_HDR_MACI:
 			hfs_put_ns(0, tmp);
 			if (entry->type == HFS_CDR_FIL) {
@@ -483,6 +551,32 @@
 			limit = 4;
 			break;
 
+		case HFS_HDR_DID:
+		        /* if it's rootinfo, stick the next available did in
+			 * the did slot. */
+			limit = 4;
+			if (entry->cnid == htonl(HFS_ROOT_CNID)) {
+				struct hfs_mdb *mdb = entry->mdb;
+				const struct hfs_name *reserved = 
+				HFS_SB(mdb->sys_mdb)->s_reserved2;
+				
+				while (reserved->Len) {
+					if (hfs_streq(reserved->Name,
+						      reserved->Len,
+						      entry->key.CName.Name,
+						      entry->key.CName.Len)) {
+						hfs_put_hl(mdb->next_id, tmp);
+						p = tmp;
+						goto hfs_did_done;
+					}
+					reserved++;
+				}
+			}
+			p = (char *) &entry->cnid;
+hfs_did_done:
+			break;
+
+		case HFS_HDR_SNAME:
 		default:
 			limit = 0;
 		}
@@ -724,6 +818,30 @@
 			limit = 32;
 			break;
 
+		case HFS_HDR_AFPI:
+			hfs_put_ns(0, tmp);
+			if ((entry->type == HFS_CDR_FIL) &&
+			    (entry->u.file.flags & HFS_FIL_LOCK)) {
+				hfs_put_hs(HFS_AFP_RDONLY, tmp + 2);
+			} else {
+				hfs_put_ns(0, tmp + 2);
+			}			
+			p = tmp;
+			limit = 4;
+			break;
+
+		case HFS_HDR_PRODOSI:
+			/* XXX: this needs to do mac->prodos translations */
+			memset(tmp, 0, 8); 
+#if 0
+			hfs_put_ns(0, tmp); /* access */
+			hfs_put_ns(0, tmp); /* type */
+			hfs_put_nl(0, tmp); /* aux type */
+#endif
+			p = tmp;
+			limit = 8;
+		        break;
+
 		case HFS_HDR_MACI:
 			hfs_put_ns(0, tmp);
 			if (entry->type == HFS_CDR_FIL) {
@@ -736,6 +854,7 @@
 			break;
 
 		case HFS_HDR_FNAME:	/* Can't rename a file this way */
+		case HFS_HDR_DID:       /* can't specify a did this way */
 		default:
 			limit = 0;
 		}
@@ -826,6 +945,9 @@
 			break;
 
 		case HFS_HDR_FNAME:	/* Can't rename a file this way */
+		case HFS_HDR_DID:       /* Can't specify a did this way */
+		case HFS_HDR_PRODOSI:   /* not implemented yet */
+		case HFS_HDR_AFPI:      /* ditto */
 		default:
 			break;
 		}
diff -u --recursive --new-file v2.2.8/linux/fs/hfs/hfs.h linux/fs/hfs/hfs.h
--- v2.2.8/linux/fs/hfs/hfs.h	Mon Dec 28 15:00:52 1998
+++ linux/fs/hfs/hfs.h	Wed May 12 13:26:34 1999
@@ -80,9 +80,24 @@
 #define HFS_FK_RSRC	0xFF
 
 /* bits in hfs_fil_entry.Flags */
-#define HFS_FIL_LOCK	0x01
-#define HFS_FIL_THD	0x02
-#define HFS_FIL_USED	0x80
+#define HFS_FIL_LOCK	0x01  /* locked */
+#define HFS_FIL_THD	0x02  /* file thread */
+#define HFS_FIL_DOPEN   0x04  /* data fork open */
+#define HFS_FIL_ROPEN   0x08  /* resource fork open */
+#define HFS_FIL_DIR     0x10  /* directory (always clear) */
+#define HFS_FIL_RSRV1   0x20  /* reserved */
+#define HFS_FIL_NOCOPY  0x40  /* copy-protected file */
+#define HFS_FIL_USED	0x80  /* open */
+
+/* bits in hfs_dir_entry.Flags. dirflags is 16 bits. */
+#define HFS_DIR_LOCK        0x01  /* locked */
+#define HFS_DIR_THD         0x02  /* directory thread */
+#define HFS_DIR_INEXPFOLDER 0x04  /* in a shared area */
+#define HFS_DIR_MOUNTED     0x08  /* mounted */
+#define HFS_DIR_DIR         0x10  /* directory (always set) */
+#define HFS_DIR_EXPFOLDER   0x20  /* share point */
+#define HFS_DIR_RSRV1       0x40  /* reserved */
+#define HFS_DIR_RSRV2       0x80  /* reserved */
 
 /* Access types used when requesting access to a B-node */
 #define HFS_LOCK_NONE	0x0000	/* Illegal */
diff -u --recursive --new-file v2.2.8/linux/fs/hfs/inode.c linux/fs/hfs/inode.c
--- v2.2.8/linux/fs/hfs/inode.c	Mon Dec 28 15:00:52 1998
+++ linux/fs/hfs/inode.c	Wed May 12 13:26:34 1999
@@ -262,7 +262,7 @@
 		HFS_I(inode)->entry = entry;
 		HFS_I(inode)->tz_secondswest = hfs_to_utc(0);
 
-		hsb->s_ifill(inode, type);
+		hsb->s_ifill(inode, type, hsb->s_version);
 		if (!hsb->s_afpd && (entry->type == HFS_CDR_FIL) &&
 		    (entry->u.file.flags & HFS_FIL_LOCK)) {
 			inode->i_mode &= ~S_IWUGO;
@@ -289,7 +289,7 @@
  * in other filesystems.  It is called by __hfs_iget() to fill in
  * the missing fields of an uninitialized inode under the CAP scheme.
  */
-void hfs_cap_ifill(struct inode * inode, ino_t type)
+void hfs_cap_ifill(struct inode * inode, ino_t type, const int version)
 {
 	struct hfs_cat_entry *entry = HFS_I(inode)->entry;
 
@@ -337,7 +337,7 @@
  * the missing fields of an uninitialized inode under the AppleDouble
  * scheme.
  */
-void hfs_dbl_ifill(struct inode * inode, ino_t type)
+void hfs_dbl_ifill(struct inode * inode, ino_t type, const int version)
 {
 	struct hfs_cat_entry *entry = HFS_I(inode)->entry;
 
@@ -378,7 +378,7 @@
  * the missing fields of an uninitialized inode under the Netatalk
  * scheme.
  */
-void hfs_nat_ifill(struct inode * inode, ino_t type)
+void hfs_nat_ifill(struct inode * inode, ino_t type, const int version)
 {
 	struct hfs_cat_entry *entry = HFS_I(inode)->entry;
 
@@ -393,7 +393,8 @@
 			inode->i_nlink = 1;
 		}
 		inode->i_op = &hfs_hdr_inode_operations;
-		HFS_I(inode)->default_layout = &hfs_nat_hdr_layout;
+		HFS_I(inode)->default_layout = (version == 2) ?
+			&hfs_nat2_hdr_layout : &hfs_nat_hdr_layout;
 	} else if (entry->type == HFS_CDR_FIL) {
 		init_file_inode(inode, HFS_FK_DATA);
 		inode->i_op = &hfs_file_inode_operations;
diff -u --recursive --new-file v2.2.8/linux/fs/hfs/super.c linux/fs/hfs/super.c
--- v2.2.8/linux/fs/hfs/super.c	Sun Nov  8 14:03:06 1998
+++ linux/fs/hfs/super.c	Wed May 12 13:26:34 1999
@@ -183,6 +183,8 @@
 	hsb->s_lowercase = 0;
 	hsb->s_quiet     = 0;
 	hsb->s_afpd      = 0;
+        /* default version. 0 just selects the defaults */
+	hsb->s_version   = 0; 
 	hsb->s_conv = 'b';
 	names = '?';
 	fork = '?';
@@ -197,7 +199,15 @@
 			*value++ = 0;
 		}
 	/* Numeric-valued options */
-		if (!strcmp(this_char,"uid")) {
+		if (!strcmp(this_char, "version")) {
+			if (!value || !*value) {
+				return 0;
+			}
+			hsb->s_version = simple_strtoul(value,&value,0);
+			if (*value) {
+				return 0;
+			}
+		} else if (!strcmp(this_char,"uid")) {
 			if (!value || !*value) {
 				return 0;
 			}
diff -u --recursive --new-file v2.2.8/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.2.8/linux/fs/proc/array.c	Tue May 11 13:10:31 1999
+++ linux/fs/proc/array.c	Tue May 11 16:30:35 1999
@@ -567,7 +567,7 @@
 			}
 		} while (count++ < 16);
 	}
-#elif defined (CONFIG_ARM)
+#elif defined(__arm__)
 	{
 		unsigned long fp, lr;
 		unsigned long stack_page;
@@ -623,7 +623,7 @@
 # define KSTK_EIP(tsk) \
     (*(unsigned long *)(PT_REG(pc) + PAGE_SIZE + (unsigned long)(tsk)))
 # define KSTK_ESP(tsk)	((tsk) == current ? rdusp() : (tsk)->tss.usp)
-#elif defined(CONFIG_ARM)
+#elif defined(__arm__)
 # define KSTK_EIP(tsk)	(((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
 # define KSTK_ESP(tsk)	(((unsigned long *)(4096+(unsigned long)(tsk)))[1020])
 #elif defined(__mc68000__)
diff -u --recursive --new-file v2.2.8/linux/include/asm-arm/arch-ebsa285/irq.h linux/include/asm-arm/arch-ebsa285/irq.h
--- v2.2.8/linux/include/asm-arm/arch-ebsa285/irq.h	Tue May 11 13:10:31 1999
+++ linux/include/asm-arm/arch-ebsa285/irq.h	Tue May 11 16:30:36 1999
@@ -10,7 +10,6 @@
  *  26-Jan-1999	PJB	Don't use IACK on CATS
  *  16-Mar-1999	RMK	Added autodetect of ISA PICs
  */
-#include <linux/config.h>
 #include <asm/hardware.h>
 #include <asm/dec21285.h>
 #include <asm/irq.h>
diff -u --recursive --new-file v2.2.8/linux/include/asm-arm/arch-ebsa285/memory.h linux/include/asm-arm/arch-ebsa285/memory.h
--- v2.2.8/linux/include/asm-arm/arch-ebsa285/memory.h	Tue May 11 13:10:31 1999
+++ linux/include/asm-arm/arch-ebsa285/memory.h	Tue May 11 16:30:36 1999
@@ -15,8 +15,6 @@
 #ifndef __ASM_ARCH_MMU_H
 #define __ASM_ARCH_MMU_H
 
-#include <linux/config.h>
-
 #if defined(CONFIG_HOST_FOOTBRIDGE)
 
 /*
diff -u --recursive --new-file v2.2.8/linux/include/asm-arm/arch-rpc/io.h linux/include/asm-arm/arch-rpc/io.h
--- v2.2.8/linux/include/asm-arm/arch-rpc/io.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-rpc/io.h	Tue May 11 16:30:36 1999
@@ -28,18 +28,43 @@
  * Dynamic IO functions - let the compiler
  * optimize the expressions
  */
-#define DECLARE_DYN_OUT(fnsuffix,instr)						\
-extern __inline__ void __out##fnsuffix (unsigned int value, unsigned int port)	\
-{										\
-	unsigned long temp;							\
-	__asm__ __volatile__(							\
-	"tst	%2, #0x80000000\n\t"						\
-	"mov	%0, %4\n\t"							\
-	"addeq	%0, %0, %3\n\t"							\
-	"str" ##instr## "	%1, [%0, %2, lsl #2]	@ out"###fnsuffix	\
-	: "=&r" (temp)								\
-	: "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)	\
-	: "cc");								\
+extern __inline__ void __outb (unsigned int value, unsigned int port)
+{
+	unsigned long temp;
+	__asm__ __volatile__(
+	"tst	%2, #0x80000000\n\t"
+	"mov	%0, %4\n\t"
+	"addeq	%0, %0, %3\n\t"
+	"strb	%1, [%0, %2, lsl #2]	@ outb"
+	: "=&r" (temp)
+	: "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
+	: "cc");
+}
+
+extern __inline__ void __outw (unsigned int value, unsigned int port)
+{
+	unsigned long temp;
+	__asm__ __volatile__(
+	"tst	%2, #0x80000000\n\t"
+	"mov	%0, %4\n\t"
+	"addeq	%0, %0, %3\n\t"
+	"str	%1, [%0, %2, lsl #2]	@ outw"
+	: "=&r" (temp)
+	: "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
+	: "cc");
+}
+
+extern __inline__ void __outl (unsigned int value, unsigned int port)
+{
+	unsigned long temp;
+	__asm__ __volatile__(
+	"tst	%2, #0x80000000\n\t"
+	"mov	%0, %4\n\t"
+	"addeq	%0, %0, %3\n\t"
+	"str	%1, [%0, %2, lsl #2]	@ outl"
+	: "=&r" (temp)
+	: "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
+	: "cc");
 }
 
 #define DECLARE_DYN_IN(sz,fnsuffix,instr)					\
@@ -66,7 +91,6 @@
 }
 
 #define DECLARE_IO(sz,fnsuffix,instr)	\
-	DECLARE_DYN_OUT(fnsuffix,instr)	\
 	DECLARE_DYN_IN(sz,fnsuffix,instr)
 
 DECLARE_IO(char,b,"b")
@@ -74,7 +98,6 @@
 DECLARE_IO(long,l,"")
 
 #undef DECLARE_IO
-#undef DECLARE_DYN_OUT
 #undef DECLARE_DYN_IN
 
 /*
diff -u --recursive --new-file v2.2.8/linux/include/asm-arm/proc-fns.h linux/include/asm-arm/proc-fns.h
--- v2.2.8/linux/include/asm-arm/proc-fns.h	Tue May 11 13:10:32 1999
+++ linux/include/asm-arm/proc-fns.h	Tue May 11 16:30:36 1999
@@ -10,7 +10,7 @@
 
 #ifdef __KERNEL__
 
-/* forward-decare task_struct */
+/* forward-declare task_struct */
 struct task_struct;
 
 /*
diff -u --recursive --new-file v2.2.8/linux/include/asm-arm/semaphore.h linux/include/asm-arm/semaphore.h
--- v2.2.8/linux/include/asm-arm/semaphore.h	Tue May 11 13:10:32 1999
+++ linux/include/asm-arm/semaphore.h	Tue May 11 16:30:36 1999
@@ -5,7 +5,6 @@
 #define __ASM_ARM_SEMAPHORE_H
 
 #include <linux/linkage.h>
-#include <asm/system.h>
 #include <asm/atomic.h>
 
 struct semaphore {
diff -u --recursive --new-file v2.2.8/linux/include/asm-m68k/page.h linux/include/asm-m68k/page.h
--- v2.2.8/linux/include/asm-m68k/page.h	Tue May 11 13:10:32 1999
+++ linux/include/asm-m68k/page.h	Wed May 12 08:50:08 1999
@@ -1,6 +1,8 @@
 #ifndef _M68K_PAGE_H
 #define _M68K_PAGE_H
 
+#include <linux/config.h>
+
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT	12
 #define PAGE_SIZE	(1UL << PAGE_SHIFT)
diff -u --recursive --new-file v2.2.8/linux/include/asm-m68k/q40_keyboard.h linux/include/asm-m68k/q40_keyboard.h
--- v2.2.8/linux/include/asm-m68k/q40_keyboard.h	Tue May 11 13:10:32 1999
+++ linux/include/asm-m68k/q40_keyboard.h	Wed May 12 08:50:08 1999
@@ -9,10 +9,6 @@
  */
 
 
-#include <linux/config.h> /* CONFIG_MAGIC_SYSRQ */
-
-
-
 #ifdef __KERNEL__
 
 
diff -u --recursive --new-file v2.2.8/linux/include/asm-m68k/semaphore-helper.h linux/include/asm-m68k/semaphore-helper.h
--- v2.2.8/linux/include/asm-m68k/semaphore-helper.h	Tue May 11 13:10:32 1999
+++ linux/include/asm-m68k/semaphore-helper.h	Wed May 12 08:50:08 1999
@@ -9,6 +9,8 @@
  * m68k version by Andreas Schwab
  */
 
+#include <linux/config.h>
+
 /*
  * These two _must_ execute atomically wrt each other.
  */
diff -u --recursive --new-file v2.2.8/linux/include/asm-m68k/semaphore.h linux/include/asm-m68k/semaphore.h
--- v2.2.8/linux/include/asm-m68k/semaphore.h	Tue May 11 13:10:32 1999
+++ linux/include/asm-m68k/semaphore.h	Wed May 12 08:50:08 1999
@@ -1,7 +1,6 @@
 #ifndef _M68K_SEMAPHORE_H
 #define _M68K_SEMAPHORE_H
 
-#include <linux/config.h>
 #include <linux/linkage.h>
 
 #include <asm/system.h>
diff -u --recursive --new-file v2.2.8/linux/include/linux/hfs_fs.h linux/include/linux/hfs_fs.h
--- v2.2.8/linux/include/linux/hfs_fs.h	Fri Nov 27 13:09:29 1998
+++ linux/include/linux/hfs_fs.h	Wed May 12 13:26:34 1999
@@ -82,17 +82,22 @@
 #define HFS_SGL_DINF	HFS_ITYPE_1	/* %DirInfo for directory */
 
 /* IDs for elements of an AppleDouble or AppleSingle header */
-#define HFS_HDR_DATA	1
-#define HFS_HDR_RSRC	2
-#define HFS_HDR_FNAME	3
-#define HFS_HDR_COMNT	4
-#define HFS_HDR_BWICN	5
-#define HFS_HDR_CICON	6
-#define HFS_HDR_OLDI	7
-#define HFS_HDR_DATES	8
-#define HFS_HDR_FINFO	9
-#define HFS_HDR_MACI	10
-#define HFS_HDR_MAX	10
+#define HFS_HDR_DATA	1   /* data fork */
+#define HFS_HDR_RSRC	2   /* resource fork */
+#define HFS_HDR_FNAME	3   /* full (31-character) name */
+#define HFS_HDR_COMNT	4   /* comment */
+#define HFS_HDR_BWICN	5   /* b/w icon */
+#define HFS_HDR_CICON	6   /* color icon info */
+#define HFS_HDR_OLDI	7   /* old file info */
+#define HFS_HDR_DATES	8   /* file dates info */
+#define HFS_HDR_FINFO	9   /* Finder info */
+#define HFS_HDR_MACI	10  /* Macintosh info */
+#define HFS_HDR_PRODOSI 11  /* ProDOS info */
+#define HFS_HDR_MSDOSI  12  /* MSDOS info */
+#define HFS_HDR_SNAME   13  /* short name */
+#define HFS_HDR_AFPI    14  /* AFP file info */
+#define HFS_HDR_DID     15  /* directory id */
+#define HFS_HDR_MAX	16
 
 /*
  * There are three time systems.  All three are based on seconds since
@@ -136,26 +141,7 @@
 };
 
 /* 
- * Default header layout for Netatalk
- */
-struct hfs_nat_hdr {
-	hfs_lword_t	magic;
-	hfs_lword_t	version;
-	hfs_byte_t	homefs[16];
-	hfs_word_t	entries;
-	hfs_byte_t	descrs[60];
-	hfs_byte_t	real_name[255];	/* id=3 */
-	hfs_byte_t	comment[200];	/* id=4 XXX: not yet implemented */
-	hfs_lword_t	create_time;	/* \       */
-	hfs_lword_t	modify_time;	/*  |      */
-	hfs_lword_t	backup_time;	/*  | id=7 */
-	hfs_word_t	filler;		/*  |      */
-	hfs_word_t	attr;		/* /       */
-	hfs_byte_t	finderinfo[32]; /* id=9 */
-};
-
-/* 
- * Default header layout for AppleDouble
+ * Default header layout for Netatalk and AppleDouble
  */
 struct hfs_dbl_hdr {
 	hfs_lword_t	magic;
@@ -163,23 +149,37 @@
 	hfs_byte_t	filler[16];
 	hfs_word_t	entries;
 	hfs_byte_t	descrs[12*HFS_HDR_MAX];
-	hfs_u32		create_time;	/* \	   */
-	hfs_u32		modify_time;	/*  | id=8 */
-	hfs_u32		backup_time;	/*  |	   */
-	hfs_u32		access_time;	/* /	   */
+	hfs_byte_t	real_name[255];	/* id=3 */
+	hfs_byte_t	comment[200];	/* id=4 XXX: not yet implemented */
+	hfs_u32		create_time;	/* \	          */
+	hfs_u32		modify_time;	/*  | id=8 (or 7) */
+	hfs_u32		backup_time;	/*  |	          */
+	hfs_u32         access_time;    /* /  (attributes with id=7) */
 	hfs_u8		finderinfo[32]; /* id=9 */
 	hfs_u32		fileinfo;	/* id=10 */
-	hfs_u8		real_name[32];	/* id=3 */
-	hfs_u8		comment[200];	/* id=4 XXX: not yet implemented */
+        hfs_u32         cnid;           /* id=15 */
+	hfs_u8          short_name[12]; /* id=13 */
+	hfs_u8          prodosi[8];     /* id=11 */
 };
 
+
 /* finder metadata for CAP */
 struct hfs_cap_info {
 	hfs_byte_t	fi_fndr[32];	/* Finder's info */
-	hfs_word_t	fi_attr;	/* AFP attributes */
-#define HFS_AFP_WRI		0x020	/* Write inhibit bit */
-#define HFS_AFP_RNI		0x080	/* Rename inhibit bit (AFP >= 2.0) */
-#define HFS_AFP_DEI		0x100	/* Delete inhibit bit (AFP >= 2.0) */
+	hfs_word_t	fi_attr;	/* AFP attributes (f=file/d=dir) */
+#define HFS_AFP_INV             0x001   /* Invisible bit (f/d) */
+#define HFS_AFP_EXPFOLDER       0x002   /* exported folder (d) */
+#define HFS_AFP_MULTI           0x002   /* Multiuser bit (f) */
+#define HFS_AFP_SYS             0x004   /* System bit (f/d) */
+#define HFS_AFP_DOPEN           0x008   /* data fork already open (f) */
+#define HFS_AFP_MOUNTED         0x008   /* mounted folder (d) */
+#define HFS_AFP_ROPEN           0x010   /* resource fork already open (f) */
+#define HFS_AFP_INEXPFOLDER     0x010   /* folder in shared area (d) */
+#define HFS_AFP_WRI		0x020	/* Write inhibit bit (readonly) (f) */
+#define HFS_AFP_BACKUP          0x040   /* backup needed bit (f/d)  */
+#define HFS_AFP_RNI		0x080	/* Rename inhibit bit (f/d) */
+#define HFS_AFP_DEI		0x100	/* Delete inhibit bit (f/d) */
+#define HFS_AFP_NOCOPY          0x400   /* Copy protect bit (f) */
 #define HFS_AFP_RDONLY	(	HFS_AFP_WRI|HFS_AFP_RNI|HFS_AFP_DEI)
 	hfs_byte_t	fi_magic1;	/* Magic number: */
 #define HFS_CAP_MAGIC1		0xFF
@@ -273,6 +273,7 @@
 extern const struct hfs_hdr_layout hfs_dbl_fil_hdr_layout;
 extern const struct hfs_hdr_layout hfs_dbl_dir_hdr_layout;
 extern const struct hfs_hdr_layout hfs_nat_hdr_layout;
+extern const struct hfs_hdr_layout hfs_nat2_hdr_layout;
 extern const struct hfs_hdr_layout hfs_sngl_hdr_layout;
 
 /* inode.c */
@@ -280,10 +281,10 @@
 extern int hfs_notify_change(struct dentry *, struct iattr *);
 extern struct inode *hfs_iget(struct hfs_cat_entry *, ino_t, struct dentry *);
 
-extern void hfs_cap_ifill(struct inode *, ino_t);
-extern void hfs_dbl_ifill(struct inode *, ino_t);
-extern void hfs_nat_ifill(struct inode *, ino_t);
-extern void hfs_sngl_ifill(struct inode *, ino_t);
+extern void hfs_cap_ifill(struct inode *, ino_t, const int);
+extern void hfs_dbl_ifill(struct inode *, ino_t, const int);
+extern void hfs_nat_ifill(struct inode *, ino_t, const int);
+extern void hfs_sngl_ifill(struct inode *, ino_t, const int);
 
 /* super.c */
 extern struct super_block *hfs_read_super(struct super_block *,void *,int);
diff -u --recursive --new-file v2.2.8/linux/include/linux/hfs_fs_sb.h linux/include/linux/hfs_fs_sb.h
--- v2.2.8/linux/include/linux/hfs_fs_sb.h	Sun Jan  4 10:40:17 1998
+++ linux/include/linux/hfs_fs_sb.h	Wed May 12 13:26:34 1999
@@ -16,7 +16,7 @@
 
 typedef int (*hfs_namein_fn) (char *, const struct hfs_name *);
 typedef void (*hfs_nameout_fn) (struct hfs_name *, const char *, int);
-typedef void (*hfs_ifill_fn) (struct inode *, ino_t);
+typedef void (*hfs_ifill_fn) (struct inode *, ino_t, const int);
 
 /*
  * struct hfs_sb_info
@@ -30,6 +30,7 @@
 						   changing owner or mode? */
 	int			s_lowercase;	/* Map names to lowercase? */
 	int			s_afpd;		/* AFPD compatible mode? */
+	int                     s_version;      /* version info */
 	hfs_namein_fn		s_namein;	/* The function used to
 						   map Mac filenames to
 						   Linux filenames */
diff -u --recursive --new-file v2.2.8/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v2.2.8/linux/include/linux/skbuff.h	Fri Oct  9 13:27:16 1998
+++ linux/include/linux/skbuff.h	Thu May 13 10:33:17 1999
@@ -449,6 +449,14 @@
  *	Add data to an sk_buff
  */
  
+extern __inline__ unsigned char *__skb_put(struct sk_buff *skb, unsigned int len)
+{
+	unsigned char *tmp=skb->tail;
+	skb->tail+=len;
+	skb->len+=len;
+	return tmp;
+}
+
 extern __inline__ unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
 {
 	unsigned char *tmp=skb->tail;
@@ -461,6 +469,13 @@
 here:		;
 	}
 	return tmp;
+}
+
+extern __inline__ unsigned char *__skb_push(struct sk_buff *skb, unsigned int len)
+{
+	skb->data-=len;
+	skb->len+=len;
+	return skb->data;
 }
 
 extern __inline__ unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
diff -u --recursive --new-file v2.2.8/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.2.8/linux/include/net/tcp.h	Tue May 11 13:10:32 1999
+++ linux/include/net/tcp.h	Thu May 13 10:33:17 1999
@@ -728,7 +728,7 @@
  */
 extern __inline__ __u32 tcp_recalc_ssthresh(struct tcp_opt *tp)
 {
-	__u32 snd_wnd_packets = tp->snd_wnd / tp->mss_cache;
+	__u32 snd_wnd_packets = tp->snd_wnd / max(tp->mss_cache, 1);
 
 	return max(min(snd_wnd_packets, tp->snd_cwnd) >> 1, 2);
 }
diff -u --recursive --new-file v2.2.8/linux/net/ipv4/ip_masq_quake.c linux/net/ipv4/ip_masq_quake.c
--- v2.2.8/linux/net/ipv4/ip_masq_quake.c	Mon Feb 23 18:12:12 1998
+++ linux/net/ipv4/ip_masq_quake.c	Tue May 11 16:30:35 1999
@@ -44,7 +44,7 @@
 
 struct quake_priv_data {
 	/* Have we seen a client connect message */
-	char	cl_connect;
+	signed char	cl_connect;
 };
 
 static int
