diff -urN -X /home/leigh/.diffex linuxppc_2_4_devel/Documentation/Configure.help linuxppc_2_4_devel-local/Documentation/Configure.help
--- linuxppc_2_4_devel/Documentation/Configure.help	Fri Jun  7 19:20:18 2002
+++ linuxppc_2_4_devel-local/Documentation/Configure.help	Mon Jun 10 19:40:26 2002
@@ -14769,6 +14769,15 @@
   This option will enlarge your kernel by about 67 KB. Several
   programs depend on this, so everyone should say Y here.
 
+IBM E15 framebuffer support
+CONFIG_FB_IBME15
+  This is the framebuffer driver for the IBM E15 graphics card found in
+  IBM 6050, 6070 and 7248 PowerPC machines. Say Y here if you have one
+  of these machines. The E15 is actually just an S3 Vision 864 paired
+  with an S3 SDAC, so other cards with that combination of chips may
+  work. Saying Y to this on non-PReP non-PowerPC machines may have
+  unexpected effects.
+
 Support for PReP Residual Data
 CONFIG_PREP_RESIDUAL
   Some PReP systems have residual data passed to the kernel by the
diff -urN -X /home/leigh/.diffex linuxppc_2_4_devel/drivers/video/Config.in linuxppc_2_4_devel-local/drivers/video/Config.in
--- linuxppc_2_4_devel/drivers/video/Config.in	Fri Jun  7 19:18:52 2002
+++ linuxppc_2_4_devel-local/drivers/video/Config.in	Mon Jun 10 20:13:22 2002
@@ -78,6 +78,7 @@
       bool '  Chips 65550 display support' CONFIG_FB_CT65550
       bool '  IMS Twin Turbo display support' CONFIG_FB_IMSTT
       tristate '  S3 Trio display support' CONFIG_FB_S3TRIO
+      tristate '  IBM E15 display support' CONFIG_FB_IBME15
       bool '  VESA VGA graphics console' CONFIG_FB_VESA
       tristate '  VGA 16-color graphics console' CONFIG_FB_VGA16
       if [ "$CONFIG_8xx" = "y" ]; then
@@ -289,7 +290,8 @@
 	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \
 	   "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \
 	   "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \
-	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
+	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \
+	   "$CONFIG_FB_IBME15" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB8 y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
@@ -310,7 +312,8 @@
 	      "$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \
 	      "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
-	      "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" ]; then
+	      "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" -o \
+	      "$CONFIG_FB_IBME15" = "y" ]; then
 	    define_tristate CONFIG_FBCON_CFB8 m
 	 fi
       fi
diff -urN -X /home/leigh/.diffex linuxppc_2_4_devel/drivers/video/Makefile linuxppc_2_4_devel-local/drivers/video/Makefile
--- linuxppc_2_4_devel/drivers/video/Makefile	Fri Jun  7 19:19:02 2002
+++ linuxppc_2_4_devel-local/drivers/video/Makefile	Mon Jun 10 20:09:58 2002
@@ -68,6 +68,7 @@
 obj-$(CONFIG_FB_CLGEN)            += clgenfb.o fbgen.o
 obj-$(CONFIG_FB_TRIDENT)          += tridentfb.o fbgen.o
 obj-$(CONFIG_FB_S3TRIO)           += S3triofb.o
+obj-$(CONFIG_FB_IBME15)           += ibm_e15fb.o fbgen.o
 obj-$(CONFIG_FB_TGA)              += tgafb.o fbgen.o
 obj-$(CONFIG_FB_LYNX)             += lynxfb.o
 obj-$(CONFIG_FB_VESA)             += vesafb.o 
diff -urN -X /home/leigh/.diffex linuxppc_2_4_devel/drivers/video/fbmem.c linuxppc_2_4_devel-local/drivers/video/fbmem.c
--- linuxppc_2_4_devel/drivers/video/fbmem.c	Fri Jun  7 19:19:46 2002
+++ linuxppc_2_4_devel-local/drivers/video/fbmem.c	Mon Jun 10 19:51:27 2002
@@ -87,6 +87,8 @@
 extern int virgefb_setup(char*);
 extern int resolver_video_setup(char*);
 extern int s3triofb_init(void);
+extern int ibm_e15fb_init(void);
+extern int ibm_e15fb_setup(char *options);
 extern int vesafb_init(void);
 extern int vesafb_setup(char*);
 extern int vga16fb_init(void);
@@ -215,6 +217,9 @@
 #ifdef CONFIG_FB_S3TRIO
 	{ "s3trio", s3triofb_init, NULL },
 #endif 
+#ifdef CONFIG_FB_IBME15
+	{ "ibm_e15", ibm_e15fb_init, ibm_e15fb_setup },
+#endif 
 #ifdef CONFIG_FB_FM2
 	{ "fm2fb", fm2fb_init, fm2fb_setup },
 #endif 
diff -urN -X /home/leigh/.diffex linuxppc_2_4_devel/drivers/video/ibm_e15fb.c linuxppc_2_4_devel-local/drivers/video/ibm_e15fb.c
--- linuxppc_2_4_devel/drivers/video/ibm_e15fb.c	Thu Jan  1 01:00:00 1970
+++ linuxppc_2_4_devel-local/drivers/video/ibm_e15fb.c	Mon Jun 10 20:25:33 2002
@@ -0,0 +1,1087 @@
+/*
+ * linux/drivers/video/ibm_e15fb.c -- Frame buffer device for the S3 864
+ * + SDAC combination built into an IBM PPS 850.
+ *
+ *  Currently this only supports 8bpp with no acceleration.
+ *
+ *  Based on skeletonfb.c created 28 Dec 1997 by Geert Uytterhoeven
+ *  David Monro Mar 11 2000
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ * Version	Comments
+ * 0.1		Initial version
+ *
+ * 0.2		Added support for modes up to 1024x768, dot clock up to
+ * 		67.5 MHz. Forced the mclock to 60 MHz or I got horrible
+ * 		snow. Added soft blanking code (palette manipulation).
+ *
+ * 0.3		Fix for people using CONFIG_ALL_PPC - use isa_mem_base
+ * 		instead of PREP_ISA_MEM_BASE etc.
+ *
+ *
+ * TODO:
+ * Pixmux mode for higher clocks.
+ * Truecolour modes (much harder)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/selection.h>
+
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <linux/ioport.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+
+#include <linux/pci.h>
+
+#include "ibm_e15fb.h"
+#include "vgaregs.h"
+
+static char ibm_e15_name[] = "IBM_E15";
+
+/* Must fix this - discuss PCI resources with Gabriel */
+#define DEFAULT_VIDBASE 0x20000000
+
+#define VIDSIZE (2*1024*1024)
+
+static int screen_cleared = 0;
+
+
+    /*
+     *  If your driver supports multiple boards, you should make these arrays,
+     *  or allocate them dynamically (using kmalloc()).
+     */
+
+static struct ibm_e15fb_info fb_info;
+static int device_present = 0;
+static struct display disp;
+struct fbgen_hwswitch ibm_e15_switch;
+unsigned char palette_save[256*3];
+
+/*
+ * Prefined Video Modes
+ */
+static const struct {
+	const char *name;
+	struct fb_var_screeninfo var;
+} ibm_e15fb_predefined[] __initdata =
+{
+    { "640x480-60",
+        { 640, 480, 640, 480, 0, 0, 8, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, -1, FB_ACCEL_NONE, 39722, 40, 24, 32, 11, 96, 2,
+	0,
+	FB_VMODE_NONINTERLACED
+        }
+    }
+};
+
+#define NUM_TOTAL_MODES	arraysize(ibm_e15fb_predefined)
+static struct fb_var_screeninfo ibm_e15fb_default;
+
+/* Interfaces */
+int ibm_e15fb_init(void);
+void ibm_e15fb_cleanup(struct fb_info *info);
+int ibm_e15fb_setup(char *options);
+
+void ibm_e15_detect(void);
+int ibm_e15_encode_fix(struct fb_fix_screeninfo *fix, const
+    void *par, struct fb_info_gen *info);
+int ibm_e15_decode_var(const struct fb_var_screeninfo *var, void *par,
+    struct fb_info_gen *info);
+int ibm_e15_encode_var(struct fb_var_screeninfo *var, const
+    void *par, struct fb_info_gen *info);
+void ibm_e15_get_par(void *par, struct fb_info_gen *info);
+void ibm_e15_set_par(const void *par, struct fb_info_gen *info);
+int ibm_e15_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+     unsigned *blue, unsigned *transp, struct fb_info *info);
+int ibm_e15_setcolreg(unsigned regno, unsigned red, unsigned green,
+     unsigned blue, unsigned transp, struct fb_info *info);
+
+int ibm_e15fb_update_var(int con, struct fb_info *info);
+
+static int ibm_e15_pan_display(const struct fb_var_screeninfo *var,
+	struct fb_info_gen *info);
+int ibm_e15_blank(int blank_mode, struct fb_info_gen *info);
+void ibm_e15_set_disp(const void *par, struct display *disp,
+	 struct fb_info_gen *info);
+
+/* Internal interfaces */
+static int ibm_e15fb_open(struct fb_info *info, int user);
+static int ibm_e15fb_release(struct fb_info *info, int user);
+static int ibm_e15_calcclock(long clockfreq, int *m ,int *n1, int*n2);
+
+/* ------------------- chipset specific functions -------------------------- */
+
+
+void ibm_e15_detect(void)
+{
+    /*
+     *  This function should detect the current video mode settings and store
+     *  it as the default video mode
+     */
+
+    struct pci_dev *pcidev;
+    int retval;
+
+    fb_info.fb_phys_membase = 0xdeadbeef;
+    fb_info.fb_virt_membase = 0xdeadbeef;
+
+    pcidev = pci_find_device(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_864_2,
+NULL);
+    if(!pcidev) {
+	printk(KERN_ERR "%s: could not find S3 864 in system\n",
+		ibm_e15_name);
+	return;
+    }
+    retval = pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &fb_info.fb_phys_membase);
+    if (retval != PCIBIOS_SUCCESSFUL) {
+	printk(KERN_ERR "%s: pci_read_config_dword failed, error was %d\n",
+		ibm_e15_name, retval);
+	return;
+    }
+    if (fb_info.fb_phys_membase == 0xdeadbeef) {
+	printk(KERN_ERR "%s: pci_read_config_dword returned sucess but"
+	    " didn't set a value?!?\n", ibm_e15_name);
+	return;
+    }
+    if (fb_info.fb_phys_membase == 0) {
+	printk(KERN_WARNING "%s: No PCI linear framebuffer base address "
+	    " assigned to 864.\n", ibm_e15_name);
+	printk(KERN_WARNING "%s: This is normal. Using default of 0x%08x.\n",
+	    ibm_e15_name, DEFAULT_VIDBASE);
+	fb_info.fb_phys_membase = DEFAULT_VIDBASE;
+	retval = pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_0,
+		fb_info.fb_phys_membase);
+	if (retval != PCIBIOS_SUCCESSFUL) {
+		printk(KERN_ERR "%s: pci_write_config_dword failed, error was %d\n",
+		ibm_e15_name, retval);
+		return;
+	}
+    }
+    printk(KERN_INFO "%s: detected S3 864, linear frame buffer at 0x%08x\n",
+	ibm_e15_name, fb_info.fb_phys_membase);
+
+    fb_info.fb_phys_membase += isa_mem_base;
+
+    device_present = 1;
+    request_region(0x3c0, 32, "ibm_e15");
+    fb_info.fb_virt_membase = (u32)ioremap(fb_info.fb_phys_membase, VIDSIZE);
+    printk(KERN_INFO "Video ram virt base = %p\n", (char*)fb_info.fb_virt_membase);
+    return;
+}
+
+int ibm_e15_encode_fix(struct fb_fix_screeninfo *fix, const
+	void *par, struct fb_info_gen *info)
+{
+    struct ibm_e15fb_par *mpar = (struct ibm_e15fb_par *) par;
+    /*
+     *  This function should fill in the 'fix' structure based on the values
+     *  in the `par' structure.
+     */
+
+    sprintf(fix->id, "IBM E15");
+    fix->smem_start = (char*)fb_info.fb_phys_membase;
+    fix->smem_len = VIDSIZE;	/* Need to get this from the card */
+    fix->type = FB_TYPE_PACKED_PIXELS;	/* No plane modes yet */
+    fix->type_aux = 0;	/* Only for plane modes */
+    fix->visual = FB_VISUAL_PSEUDOCOLOR; /* Only 8bit for now */
+    fix->xpanstep = 0;
+    fix->ypanstep = 0;
+    fix->ywrapstep = 0;
+    fix->line_length = mpar->xres; /* 8bit = 1byte/pixel */
+    fix->accel = FB_ACCEL_NONE;
+
+    return 0;
+}
+
+int ibm_e15_decode_var(const struct fb_var_screeninfo *var, void *par,
+    struct fb_info_gen *info)
+{
+    /*
+     *  Get the video params out of 'var'. If a value doesn't fit, round it up,
+     *  if it's too big, return -EINVAL.
+     *
+     *  Suggestion: Round up in the following order: bits_per_pixel, xres,
+     *  yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
+     *  bitfields, horizontal timing, vertical timing.
+     */
+
+    struct ibm_e15fb_par *mpar = (struct ibm_e15fb_par *) par;
+    int retval;
+
+    if (var->bits_per_pixel > 8) return -EINVAL;
+    if (var->xres >1024) return -EINVAL;
+    if (var->yres >768) return -EINVAL;
+    if (1000000000/var->pixclock > SDAC_MAXNONMUXCLOCK) return -EINVAL;
+
+    if ((var->xres < 640) || (var->yres < 480)) {
+	    /* This is needed because we set the enhanced mode bits on
+	     * the card which assume 640x480 or better. I don't think
+	     * anybody will seriously want less than that anyway.
+	     */
+	    var = &ibm_e15fb_default;
+    }
+
+    mpar->freq = 1000000000/var->pixclock;
+    retval = ibm_e15_calcclock(1000000000/var->pixclock, &(mpar->clock_m),
+	    &(mpar->clock_n1), &(mpar->clock_n2));
+    if (retval != 0) {
+	    return -EINVAL;
+    }
+    mpar->xres = var->xres;
+    mpar->yres = var->yres;
+    mpar->xfrontporch = var->right_margin;
+    mpar->xsync = var->hsync_len;
+    mpar->xbackporch = var->left_margin;
+    mpar->yfrontporch = var->lower_margin;
+    mpar->ysync = var->vsync_len;
+    mpar->ybackporch = var->upper_margin;
+    mpar->bpp = var->bits_per_pixel;
+    mpar->syncflags = var->sync;
+
+#if 0
+    /* pixclock in picos, htotal in pixels, vtotal in scanlines */
+    if (!fbmon_valid_timings(pixclock, htotal, vtotal, info))
+	    return -EINVAL;
+#endif
+
+    return 0;
+}
+
+int ibm_e15_encode_var(struct fb_var_screeninfo *var, const
+void *par, struct fb_info_gen *info)
+{
+    /*
+     *  Fill the 'var' structure based on the values in 'par' and maybe other
+     *  values read out of the hardware.
+     */
+
+    struct ibm_e15fb_par *mpar = (struct ibm_e15fb_par *) par;
+
+    if (!var) {
+	    return EINVAL;
+    }
+    var->xres = mpar->xres;
+    var->yres = mpar->yres;
+    var->xres_virtual = mpar->xres;
+    var->yres_virtual = mpar->yres;
+    var->xoffset = 0;
+    var->yoffset = 0;
+    var->bits_per_pixel = 8;
+    var->grayscale = 0;
+    var->red.offset = var->green.offset = var->blue.offset = 0;
+    var->red.length = var->green.length = var->blue.length = 8;
+    var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
+    var->transp.offset = var->transp.length = var->transp.msb_right = 0;
+    var->nonstd = 0;
+    var->activate = 0;
+    var->accel_flags = 0;
+    var->pixclock = 1000000000/mpar->freq;
+    var->left_margin = mpar->xbackporch;
+    var->right_margin = mpar->xfrontporch;
+    var->upper_margin = mpar->ybackporch;
+    var->lower_margin = mpar->yfrontporch;
+    var->hsync_len = mpar->xsync;
+    var->vsync_len = mpar->ysync;
+    var->sync = mpar->syncflags;
+    var->vmode = FB_VMODE_NONINTERLACED;
+
+    return 0;
+}
+
+void ibm_e15_get_par(void *par, struct fb_info_gen *info)
+{
+    /*
+     *  Fill the hardware's 'par' structure.
+     */
+
+    struct ibm_e15fb_par *mpar = (struct ibm_e15fb_par *) par;
+
+    *mpar = fb_info.current_par;
+}
+
+static int ibm_e15_calcclock(long clockfreq, int *m ,int *n1, int *n2)
+{
+	int error;
+
+	if (clockfreq > SDAC_MAXNONMUXCLOCK) {
+		printk(KERN_ERR "%s: Requested clock %ld greater than maximum %d.\n",
+			ibm_e15_name, clockfreq, SDAC_MAXNONMUXCLOCK);
+		return -EINVAL;
+	}
+	for (*n2 = SDAC_MAX_N2; *n2 >= SDAC_MIN_N2; (*n2)--) {
+		if ((clockfreq*(1<<*n2)) < SDAC_MAX_VCO)
+			break;
+	}
+	if (*n2 < SDAC_MIN_N2) {
+		/* This should never happen */
+		printk(KERN_ERR "%s: unable to find suitable n2 for clock frequency %ld.\n",
+			ibm_e15_name, clockfreq);
+		return -EINVAL;
+	}
+
+	for (*m = SDAC_MIN_M; *m <= SDAC_MAX_M; (*m)++) {
+		for (*n1 = SDAC_MIN_N1; *n1 <= SDAC_MAX_N1; (*n1)++) {
+			error = (clockfreq) - ((*m*SDAC_REFCLK)/(*n1*(1<<*n2)));
+			if (error < 0) error = -error;
+			if ((error == 0) || ((clockfreq/error) > SDAC_MAXERR)) {
+				break;
+			}
+		}
+		if ((error == 0) || ((clockfreq/error) > SDAC_MAXERR)) {
+			break;
+		}
+	}
+	if ((*m > SDAC_MAX_M) || (*n1 > SDAC_MAX_N1)) {
+		printk(KERN_ERR "%s: unable to find suitable m and n1 for clock frequency %ld.\n",
+			ibm_e15_name, clockfreq);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void ibm_e15_set_crts(const  struct ibm_e15fb_par *par)
+{
+    u8 cregs[VGA_CRTC_REGS], CR55, SDI;
+    int i, tmp, itmp;
+    int m, n = 255; /* extended memctl paramters */
+
+    int xvis =  par->xres/8, xss = xvis + par->xfrontporch/8, xse = xss
+	    + par->xsync/8, xtot = xse + par->xbackporch/8;
+    int yvis = par->yres, yss = yvis + par->yfrontporch, yse = yss +
+	    par->ysync, ytot = yse + par->ybackporch;
+
+    cregs[VGA_CRTC_H_TOTAL] = xtot - 5;
+    cregs[VGA_CRTC_H_DISP] = xvis - 1;
+    cregs[VGA_CRTC_H_BLANK_START] = xss -1;
+    cregs[VGA_CRTC_H_BLANK_END] = (xse & 0x1F) | 0x80;
+    cregs[VGA_CRTC_H_SYNC_START] = xss;
+    cregs[VGA_CRTC_H_SYNC_END] = ((xse & 0x20) << 2) | (xse & 0x1F);
+
+    cregs[VGA_CRTC_V_TOTAL] = (ytot -2) & 0xFF;
+    /* VGA_CRTC_OVERFLOW is a mess - we need:
+     * 0  Bit 8 of Vertical Total (3d4h index 6)
+     * 1  Bit 8 of Vertical Display End (3d4h index 12h)
+     * 2  Bit 8 of Vertical Retrace Start (3d4h index 10h)
+     * 3  Bit 8 of Start Vertical Blanking (3d4h index 15h)
+     * 4  Bit 8 of Line Compare Register (3d4h index 18h)
+     * 5  Bit 9 of Vertical Total (3d4h index 6)
+     * 6  Bit 9 of Vertical Display End (3d4h index 12h)
+     * 7  Bit 9 of Vertical Retrace Start (3d4h index 10h)
+     */
+    cregs[VGA_CRTC_OVERFLOW] = (((ytot - 2) & 0x100) >> 8)
+	| (((yvis - 1) & 0x100) >> 7)
+	| ((yss & 0x100) >> 6)
+	| ((yss & 0x100) >> 5)
+	| 0x10 /* Line compare disabled */
+	| (((ytot - 2) & 0x200) >> 4)
+	| (((yvis -1) & 0x200) >> 3)
+	| ((yss & 0x200) >> 2);
+    /* that was bletcherous.... */
+    cregs[VGA_CRTC_PRESET_ROW] = 0;
+
+    /* We don't support vertical doubling so this is just:
+     * 5  Bit 9 of Start Vertical Blanking
+     * 6  Bit 9 of Line Compare Register (always 1)
+     */
+
+    cregs[VGA_CRTC_MAX_SCAN] = ((yss & 0x200) >>4) | 0x40;
+    cregs[VGA_CRTC_CURSOR_START] = 0x00;
+    cregs[VGA_CRTC_CURSOR_END] = 0x0;
+    cregs[VGA_CRTC_START_HI] = 0;	/* No virtual panning */
+    cregs[VGA_CRTC_START_LO] = 0;
+    cregs[VGA_CRTC_CURSOR_HI] = 0; /* Cursor is off anyway */
+    cregs[VGA_CRTC_CURSOR_LO] = 0;
+    cregs[VGA_CRTC_V_SYNC_START] = yss & 0xFF;
+    cregs[VGA_CRTC_V_SYNC_END] = (yse & 0x0F) | 0x20; /* disable irq */
+    cregs[VGA_CRTC_V_DISP_END] = (yvis -1) & 0xFF;
+#if 0	/* BUSWIDTH */
+    cregs[VGA_CRTC_OFFSET] = (par->xres >> 4) & 0xFF;  /* bytes/line */
+#else
+    /* From the S3 init code in the x servver */
+    cregs[VGA_CRTC_OFFSET] = (par->xres >> 3) & 0xFF;  /* bytes/line */
+#endif
+    cregs[VGA_CRTC_UNDERLINE] = 0x00;
+    cregs[VGA_CRTC_V_BLANK_START] = yss & 0xFF;
+    cregs[VGA_CRTC_V_BLANK_END] = (yse +1) & 0xFF;
+#if 0	/* BUSWIDTH */
+    cregs[VGA_CRTC_MODE] = 0xC3;
+#else
+    /* From the S3 init code in the xserver */
+    cregs[VGA_CRTC_MODE] = 0xE3;
+#endif
+    cregs[VGA_CRTC_LINE_COMPARE] = 0xFF;
+
+    /* Deprotect registers 0-7 */
+    outb_p(VGA_CRTC_V_SYNC_END, VGA_CRT_IC);
+    outb_p(cregs[VGA_CRTC_V_SYNC_END] & 0x7f, VGA_CRT_DC);
+
+    for (i = 0; i < VGA_CRT_C; i ++) {
+	outb_p(i, VGA_CRT_IC);
+	outb_p(cregs[i], VGA_CRT_DC);
+    }
+
+    /* Reprotect the registers 0-7 */
+    outb_p(VGA_CRTC_V_SYNC_END, VGA_CRT_IC);
+    outb_p(cregs[VGA_CRTC_V_SYNC_END] | 0x80, VGA_CRT_DC);
+
+    /* unlock '864 specials */
+    outb_p(0x38, VGA_CRT_IC);
+    outb_p(0x48, VGA_CRT_DC);
+    outb_p(0x39, VGA_CRT_IC);
+    outb_p(0xa5, VGA_CRT_DC);
+
+    /* Program them */
+
+    /* CR31 */
+    outb_p(0x31, VGA_CRT_IC);
+    if (par->xres == 2048) {
+	outb_p(0x8f, VGA_CRT_DC);
+    } else {
+	outb_p(0x8d, VGA_CRT_DC);
+    }
+
+    /* CR32-34 */
+    outb_p(0x32, VGA_CRT_IC);
+    outb_p(0x00, VGA_CRT_DC);
+    outb_p(0x33, VGA_CRT_IC);
+    outb_p(0x20, VGA_CRT_DC);
+    outb_p(0x34, VGA_CRT_IC);
+    outb_p(0x10, VGA_CRT_DC);
+
+    /* CR66 - must be set before CR3A */
+    outb_p(0x66, VGA_CRT_IC);
+    tmp = inb_p(VGA_CRT_DC);
+    outb_p(tmp | 0x80, VGA_CRT_DC);
+
+    /* CR3A */
+    outb_p(0x3A, VGA_CRT_IC);	/* enable enhanced mode  for 256 */
+    outb_p(0xb5, VGA_CRT_DC);
+
+    /* CR3B */
+    outb_p(0x3B, VGA_CRT_IC);
+    outb_p((cregs[0] + cregs[4] + 1)/2, VGA_CRT_DC);
+
+    /* CR3C */
+    outb_p(0x3C, VGA_CRT_IC);
+    outb_p(cregs[0]/2, VGA_CRT_DC);	/* Interlace mode frame offset */
+
+    /* CR40 */
+    outb_p(0x40, VGA_CRT_IC);
+    tmp = inb_p(VGA_CRT_DC) & 0xf6;
+    outb_p(tmp | 0x01, VGA_CRT_DC);
+
+    /* CR43 */
+    outb_p(0x43, VGA_CRT_IC);	/* 8 bpp only */
+    outb_p(0x00, VGA_CRT_DC);
+
+    /* CR44 - ? */
+    outb_p(0x44, VGA_CRT_IC);
+    outb_p(0x00, VGA_CRT_DC);
+
+    /* CR45 */
+    outb_p(0x45, VGA_CRT_IC);	/* Change for more than 8bpp */
+    tmp = inb_p(VGA_CRT_DC) & 0xf2;
+    outb_p(tmp, VGA_CRT_DC);
+
+    /* CR50 - graphics engine, ignore */ 
+
+    /* CR51  - includes logical screen with hgh bits */
+    outb_p(0x51, VGA_CRT_IC);
+    tmp = (inb_p(VGA_CRT_DC) & 0xC0) | ((xvis >> 4) & 0x30);
+    outb_p(tmp, VGA_CRT_DC);
+
+    /* CR53 */
+    outb_p(0x53, VGA_CRT_IC);
+    tmp = inb_p(VGA_CRT_DC);
+    tmp &= ~0x18;	/* No mmio regs */
+    outb_p(tmp, VGA_CRT_DC);
+
+    /* CR54 memclk - this is messy */
+    /* Blech - floating point... */
+    /*
+    m = (int)((SDAC_MEMCLK/1000.0*.72+16.867)*89.736/(par->freq/1000.0+39)-21.1543);
+    */
+    m = (((((720*SDAC_MEMCLK)+16867000)/(par->freq+39000))*89736)-21154300)/1000000;
+    if (m > 31) m = 31;
+    else if (m < 0) {
+	    m = 0;
+	    n = 16;
+    }
+    outb_p(0x54, VGA_CRT_IC);
+    outb_p(m << 3, VGA_CRT_DC);
+
+    /* CR60 - adjust stuff */
+    if (n < 0) n = 0;
+    else if (n > 255) n = 255;
+    outb_p(0x60, VGA_CRT_IC);
+    outb_p(n, VGA_CRT_DC);
+
+    /* CR5E - vertical overflows */
+    outb_p(0x5E, VGA_CRT_IC);
+    i = (((ytot - 2) & 0x400) >> 10) |
+	(((yvis - 1) & 0x400) >> 9) |
+	((yss & 0x400) >> 8) |
+	((yss & 0x400) >> 6) | 0x40;
+    outb_p(i, VGA_CRT_DC);
+
+    /* calculate stuff */
+    i = (((xtot -5) & 0x100) >> 8) |
+	(((xvis -1) & 0x100) >> 7) |
+	(((xss- 1) & 0x100) >> 6) |
+	((xse & 0x100) >> 7);
+    if ((xse - xss) > 64 ) {
+	i |= 0x08;
+    }
+    if ((xse - xss) > 32) {
+	i |= 0x20;
+    }
+
+    /* CR3B - again */
+    outb_p(0x3B, VGA_CRT_IC);
+    itmp = (cregs[0] + ((i&0x01)<<8) +
+	    cregs[4] + ((i&0x10)<<4) + 1) / 2;
+    if (itmp - (cregs[4] + ((i&0x10)<<4)) < 4)  {
+	if (cregs[4] + ((i&0x10)<<4) + 4 <= cregs[0] + ((i&0x01)<<8)) 
+	    itmp = cregs[4] + ((i&0x10)<<4) + 4;
+	else
+	    itmp = cregs[0] + ((i&0x01)<<8) + 1;
+    }
+    outb_p(itmp & 0xff, VGA_CRT_DC);
+    i |= ((itmp&0x100) >> 2);
+
+    /* CR3C - again */
+    outb_p(0x3C, VGA_CRT_IC);
+    outb_p((cregs[0] + ((i&0x01)<<8)) /2, VGA_CRT_DC);
+
+    /* CR5D */
+    outb_p(0x5D, VGA_CRT_IC);
+    tmp = (inb_p(VGA_CRT_DC) & 0x80) | i;
+    outb_p(tmp, VGA_CRT_DC);
+
+#if 0	/* BUSWIDTH */
+    i = xvis + 1;	/* We have 2M ram and run 8bpp */
+#else
+    i = xvis * 2 + 1;
+#endif
+
+    /* CR61,62 */
+    outb_p(0x61, VGA_CRT_IC);
+    tmp = 0x80 | inb_p(VGA_CRT_DC) | (i >> 8);
+    outb_p(tmp, VGA_CRT_DC);
+    outb_p(0x62, VGA_CRT_IC);
+    outb_p(i & 0xff, VGA_CRT_DC);
+
+    /* CR42 */
+    outb_p(0x42, VGA_CRT_IC);	/* non-interlaced */
+    i = inb(VGA_CRT_DC);
+    outb_p(i & ~20, VGA_CRT_DC);
+
+    outb_p(0x58, VGA_CRT_IC);	/* Enable linear addressing */
+    outb_p(0x12, VGA_CRT_DC);
+
+    outb_p(0x67, VGA_CRT_IC);	/* Pixel format 0 (8bpp, no mux) */
+    outb_p(0x00, VGA_CRT_DC);
+
+    outb_p(0x6D, VGA_CRT_IC);	/* No delays on signals */
+    outb_p(0x00, VGA_CRT_DC);
+
+    /* Set the clock and other bits of the dac */
+
+    outb_p(0xef, VGA_MIS_W); /* Clock select for base VGA */
+    outb_p(0x42, VGA_CRT_IC); /* select clock 2, non-interlaced */
+    outb_p(0x02, VGA_CRT_DC);
+
+    outb_p(0x55, VGA_CRT_IC); 	/* Access the dac registers 4-7 */
+    CR55 = inb_p(VGA_CRT_DC);
+    outb_p(CR55 | 0x01, VGA_CRT_DC);
+
+    outb_p(0x00, SDAC_REG06);	/* Dac pixel format 0 (8bpp, no mux) */
+    SDI=inb_p(SDAC_REG04);
+    outb_p(0x02, SDAC_REG04); /* Select index 2 (f2) */
+    outb_p(par->clock_m - 2, SDAC_REG05);
+    outb_p(((par->clock_n1 - 2) | (par->clock_n2 << 5)), SDAC_REG05);
+
+    {
+	    int m, n1, n2;
+	    ibm_e15_calcclock(SDAC_MEMCLK, &m, &n1, &n2);
+	    outb_p(0x0A, SDAC_REG04); /* Clock 0a is memclk */
+	    outb_p(m - 2, SDAC_REG05);
+	    outb_p(((n1-2)| (n2 << 5)), SDAC_REG05);
+    }
+
+    outb_p(SDI, SDAC_REG04);
+
+    outb_p(0x55, VGA_CRT_IC);	/* Normal dac register access */
+    outb_p(CR55, VGA_CRT_DC);
+
+    /* relock '864 specials */
+    outb_p(0x38, VGA_CRT_IC);
+    outb_p(0x00, VGA_CRT_DC);
+    outb_p(0x39, VGA_CRT_IC);
+    outb_p(0x5a, VGA_CRT_DC);
+
+
+}
+
+
+void ibm_e15_set_par(const void *par, struct fb_info_gen *info)
+{
+    /*
+     *  Set the hardware according to 'par'.
+     */
+
+    int tmp;
+
+    struct ibm_e15fb_par *mpar = (struct ibm_e15fb_par *) par;
+
+    fb_info.current_par = *mpar;
+
+    outb_p(0xe3, VGA_MIS_W); /* 480 lines sync pol, 25MHz clock, colour */
+
+    /* Turn off screen  */
+    outb_p(0x01, VGA_SEQ_I);
+    tmp = inb(VGA_SEQ_D);
+    outb_p(tmp | 0x20, VGA_SEQ_D);
+
+    /* Sync reset on */
+    outb_p(0x00, VGA_SEQ_I);
+    outb_p(0x01, VGA_SEQ_D);
+
+    /* turn off screen and enable palette registers */
+    tmp = inb(VGA_IS1_RC);
+    outb(0x00, VGA_ATT_IW);
+
+    /* Program the sequencer regs */
+    outb_p(0x01, VGA_SEQ_I);
+    outb_p(0x21, VGA_SEQ_D);	 /* Sane clocking mode, screen off */
+
+    outb_p(0x02, VGA_SEQ_I);	 /* Enable all planes */
+    outb_p(0x0f, VGA_SEQ_D);
+
+    outb_p(0x03, VGA_SEQ_I);	 /* Character map? */
+    outb_p(0x00, VGA_SEQ_D);
+
+    outb_p(0x04, VGA_SEQ_I);	 /* 256 colour mode */
+    outb_p(0x0e, VGA_SEQ_D);
+
+
+    /* Program the Graphics regs */
+    outb_p(0x00, VGA_GFX_I);
+    outb_p(0x00, VGA_GFX_D);
+
+    outb_p(0x01, VGA_GFX_I);
+    outb_p(0x00, VGA_GFX_D);
+
+    outb_p(0x02, VGA_GFX_I);
+    outb_p(0x00, VGA_GFX_D);
+
+    outb_p(0x03, VGA_GFX_I);
+    outb_p(0x00, VGA_GFX_D);
+
+    outb_p(0x04, VGA_GFX_I);
+    outb_p(0x00, VGA_GFX_D);
+
+    outb_p(0x05, VGA_GFX_I);	/* 256 colour mode */
+    outb_p(0x40, VGA_GFX_D);
+
+    outb_p(0x06, VGA_GFX_I);	/* use A0000-AFFFF, graphics */
+    outb_p(0x05, VGA_GFX_D);
+
+    outb_p(0x07, VGA_GFX_I);	/* Don't ignore any bits */
+    outb_p(0x0F, VGA_GFX_D);
+
+    outb_p(0x08, VGA_GFX_I);	/* enable all bits for writing */
+    outb_p(0xFF, VGA_GFX_D);
+
+    /* Colour attribute registers */
+
+    inb_p (VGA_IS1_RC);	/* reset VGA_ATT_IW flipflop */
+    for(tmp=0;tmp<16;tmp++) {
+	outb_p(tmp, VGA_ATT_IW);
+	outb_p(tmp, VGA_ATT_IW);
+    }
+
+    outb_p(0x10, VGA_ATT_IW);	/* 8 bit pixels, graphics mode */
+    outb_p(0x41, VGA_ATT_IW);
+    
+    outb_p(0x11, VGA_ATT_IW);	/* Overscan colour */
+    outb_p(0x02, VGA_ATT_IW);
+
+    outb_p(0x12, VGA_ATT_IW);	/* Enable all planes */
+    outb_p(0x0F, VGA_ATT_IW);
+
+    outb_p(0x13, VGA_ATT_IW);	/* Don't shift the display */
+    outb_p(0x00, VGA_ATT_IW);
+
+    outb_p(0x14, VGA_ATT_IW);	
+    outb_p(0x00, VGA_ATT_IW);
+
+
+    /* Progam the VGA_CRTC regs */
+    ibm_e15_set_crts(mpar);
+
+
+    /* Reenable screen */
+    outb_p(0x01, VGA_SEQ_I);
+    tmp = inb_p(VGA_SEQ_D);
+    outb_p(tmp & 0xDF, VGA_SEQ_D);
+
+    /* Restart sequencer */
+    outb_p(0x00, VGA_SEQ_I);
+    outb_p(0x03, VGA_SEQ_D);
+
+    /* Screen enabled, palette locked */
+    tmp = inb(VGA_IS1_RC);
+    outb(0x20, VGA_ATT_IW);
+
+    if (!screen_cleared) {
+	    /* Clear the video memory */
+	    int i;
+	    for(i=0;i<VIDSIZE;i++) {
+		    writeb(0, ((char*)fb_info.fb_virt_membase)+i);
+	    }
+	    screen_cleared = 1;
+    }
+
+}
+
+int ibm_e15_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+     unsigned *blue, unsigned *transp, struct fb_info *info)
+
+{
+    /*
+     *  Read a single color register and split it into colors/transparent.
+     *  The return values must have a 16 bit magnitude.
+     *  Return != 0 for invalid regno.
+     */
+
+    unsigned char bred, bgreen, bblue;
+
+    if (regno > 244) {
+	return 1;
+    }
+    
+    outb_p(regno, VGA_PEL_IR);
+    bred = inb_p(VGA_PEL_D);
+    bgreen = inb_p(VGA_PEL_D);
+    bblue = inb_p(VGA_PEL_D);
+    *red = (bred<<10) | (bred<<4) | (bred>>2);
+    *green = (bgreen<<10) | (bgreen<<4) | (bgreen>>2);
+    *blue = (bblue<<10) | (bblue<<4) | (bblue>>2);
+    *transp = 0;
+    
+    return 0;
+}
+
+int ibm_e15_setcolreg(unsigned regno, unsigned red, unsigned green,
+			 unsigned blue, unsigned transp,
+			 struct fb_info *info)
+{
+    /*
+     *  Set a single color register. The values supplied have a 16 bit
+     *  magnitude.
+     *  Return != 0 for invalid regno.
+     */
+
+    if(regno > 255)
+	return 1;
+    red >>= 10;
+    green >>= 10;
+    blue >>= 10;
+
+    outb_p(regno, VGA_PEL_IW);
+    outb_p(red, VGA_PEL_D);
+    outb_p(green, VGA_PEL_D);
+    outb_p(blue, VGA_PEL_D);
+    return 0;
+}
+
+static int ibm_e15_pan_display(const struct fb_var_screeninfo *var,
+			   struct fb_info_gen *info)
+{
+    /*
+     *  Pan (or wrap, depending on the `vmode' field) the display using the
+     *  `xoffset' and `yoffset' fields of the `var' structure.
+     *  If the values don't fit, return -EINVAL.
+     */
+
+printk(KERN_DEBUG "ibm_e15_pan_display called?\n");
+    /* ... */
+    return -EINVAL;
+}
+
+int ibm_e15_blank(int blank_mode, struct fb_info_gen *info)
+{
+    /*
+     *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
+     *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
+     *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
+     *  to e.g. a video mode which doesn't support it. Implements VESA suspend
+     *  and powerdown modes on hardware that supports disabling hsync/vsync:
+     *    blank_mode == 2: suspend vsync
+     *    blank_mode == 3: suspend hsync
+     *    blank_mode == 4: powerdown
+     */
+
+    static int blanked = 0;
+    int i;
+
+    if (blank_mode) {
+	    outb_p(0, VGA_PEL_IR);
+	    for(i=0; i < 256*3; i++) {
+		    palette_save[i] = inb_p(VGA_PEL_D);
+	    }
+	    outb_p(0, VGA_PEL_IW);
+	    for(i=0; i < 256*3; i++) {
+		    outb_p(0, VGA_PEL_D);
+	    }
+	    blanked = 1;
+    } else {
+	    outb_p(0, VGA_PEL_IW);
+	    for(i=0; i < 256*3; i++) {
+		    outb_p(palette_save[i], VGA_PEL_D);
+	    }
+	    blanked = 0;
+    }
+
+    return 0;
+}
+
+void ibm_e15_set_disp(const void *par, struct display *disp,
+			 struct fb_info_gen *info)
+{
+    /*
+     *  Fill in a pointer with the virtual address of the mapped frame buffer.
+     *  Fill in a pointer to appropriate low level text console operations (and
+     *  optionally a pointer to help data) for the video mode `par' of your
+     *  video hardware. These can be generic software routines, or hardware
+     *  accelerated routines specifically tailored for your hardware.
+     *  If you don't have any appropriate operations, you must fill in a
+     *  pointer to dummy operations, and there will be no text output.
+     */
+
+    struct ibm_e15fb_par *_par = (struct ibm_e15fb_par*)par;
+
+    printk(KERN_INFO "%s: Text console mode: ", ibm_e15_name);
+    disp->screen_base = (unsigned char*)fb_info.fb_virt_membase;
+    switch (_par->bpp)
+    {
+#ifdef FBCON_HAS_MFB
+    case 1:
+	printk("monochrome\n");
+	disp->dispsw = &fbcon_mfb;
+	break;
+#endif
+#ifdef FBCON_HAS_CFB8
+    case 8:
+	printk("8 bit color depth\n");
+	disp->dispsw = &fbcon_cfb8;
+	break;
+#endif
+#if 0
+#ifdef FBCON_HAS_CFB16
+    case 16:
+	printk("16 bit color depth\n");
+	disp->dispsw = &fbcon_cfb16;
+	disp->dispsw_data = &fbcon_cfb16_cmap;
+	break;
+#endif
+#ifdef FBCON_HAS_CFB24
+    case 24:
+	printk("24 bit color depth\n");
+	disp->dispsw = &fbcon_cfb24;
+	disp->dispsw_data =  &fbcon_cfb24_cmap;
+	break;
+#endif
+#ifdef FBCON_HAS_CFB32
+    case 32:
+	printk("32 bit color depth\n");
+	disp->dispsw = &fbcon_cfb32;
+	disp->dispsw_data = fbcon_cfb32_cmap;
+	break;
+#endif
+#endif
+
+    default:
+	printk("unsupported color depth\n");
+	disp->dispsw = &fbcon_dummy;
+	break;
+    }
+    disp->scrollmode = SCROLL_YREDRAW;
+}
+
+
+/* ------------ Interfaces to hardware functions ------------ */
+
+
+struct fbgen_hwswitch ibm_e15_switch = {
+    ibm_e15_detect,
+    ibm_e15_encode_fix,
+    ibm_e15_decode_var,
+    ibm_e15_encode_var,
+    ibm_e15_get_par,
+    ibm_e15_set_par,
+    ibm_e15_getcolreg,
+    ibm_e15_setcolreg,
+    ibm_e15_pan_display,
+    ibm_e15_blank,
+    ibm_e15_set_disp
+};
+
+static struct fb_ops ibm_e15fb_ops = {
+owner: THIS_MODULE,
+fb_open: ibm_e15fb_open,
+fb_release: ibm_e15fb_release,
+fb_get_fix: fbgen_get_fix,
+fb_get_var: fbgen_get_var,
+fb_set_var: fbgen_set_var,
+fb_get_cmap: fbgen_get_cmap,
+fb_set_cmap: fbgen_set_cmap,
+fb_pan_display: fbgen_pan_display,
+/* fb_ioctl: fbgen_ioctl, */
+};
+
+
+
+/* ------------ Hardware Independent Functions ------------ */
+
+
+    /*
+     *  Initialization
+     */
+
+int __init ibm_e15fb_init(void)
+{
+
+    int retval;
+    printk(KERN_INFO "%s: initializing\n", ibm_e15_name);
+    fb_info.gen.parsize = sizeof(struct ibm_e15fb_par);
+    fb_info.gen.fbhw = &ibm_e15_switch;
+    fb_info.gen.fbhw->detect();
+    if(!device_present) {
+	return ENODEV;
+    }
+    strcpy(fb_info.gen.info.modename, ibm_e15_name);
+    fb_info.gen.info.changevar = NULL;
+    fb_info.gen.info.node = -1;
+    fb_info.gen.info.fbops = &ibm_e15fb_ops;
+    fb_info.gen.info.disp = &disp;
+    fb_info.gen.info.switch_con = &fbgen_switch;
+    fb_info.gen.info.updatevar = &fbgen_update_var;
+    fb_info.gen.info.blank = &fbgen_blank;
+    fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
+    /* This should give a reasonable default video mode */
+    ibm_e15fb_default = ibm_e15fb_predefined[0].var;
+    ibm_e15fb_default.activate = FB_ACTIVATE_NOW;
+    fbgen_do_set_var(&ibm_e15fb_default, 1, &fb_info.gen);
+    disp.var = ibm_e15fb_default;
+    fbgen_set_disp(-1, &fb_info.gen);
+    fbgen_install_cmap(0, &fb_info.gen);
+    if ((retval = register_framebuffer(&fb_info.gen.info)) < 0) {
+	printk(KERN_ERR "%s: register_framebuffer() failed, error was %d\n",
+	    ibm_e15_name, retval);
+	return retval;
+    }
+    printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.gen.info.node),
+	   fb_info.gen.info.modename);
+
+    /* uncomment this if your driver cannot be unloaded */
+    /* MOD_INC_USE_COUNT; */
+    return 0;
+}
+
+
+    /*
+     *  Cleanup
+     */
+
+void ibm_e15fb_cleanup(struct fb_info *info)
+{
+    /*
+     *  If your driver supports multiple boards, you should unregister and
+     *  clean up all instances.
+     */
+
+    unregister_framebuffer(info);
+    printk(KERN_INFO "%s: shutting down framebuffer\n", ibm_e15_name);
+    iounmap((char*)(fb_info.fb_virt_membase));
+}
+
+
+    /*
+     *  Setup
+     */
+
+int __init ibm_e15fb_setup(char *options)
+{
+    /* Parse user speficied options (`video=ibm_e15fb:') */
+    printk(KERN_DEBUG "dummy ibm_e15fb_setup called\n");
+    return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+    /*
+     *  Frame buffer operations
+     */
+
+static int ibm_e15fb_open(struct fb_info *info, int user)
+{
+
+    /* Nothing, only a usage count for the moment */
+    MOD_INC_USE_COUNT;
+    return 0;
+}
+
+static int ibm_e15fb_release(struct fb_info *info, int user)
+{
+
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+
+    /*
+     *  In most cases the `generic' routines (fbgen_*) should be satisfactory.
+     *  However, you're free to fill in your own replacements.
+     */
+
+
+/* ------------------------------------------------------------------------- */
+
+
+    /*
+     *  Modularization
+     */
+
+#ifdef MODULE
+int init_module(void)
+{
+    return ibm_e15fb_init();
+    return 0;
+}
+
+void cleanup_module(void)
+{
+    ibm_e15fb_cleanup(&fb_info.gen.info);
+}
+#endif /* MODULE */
diff -urN -X /home/leigh/.diffex linuxppc_2_4_devel/drivers/video/ibm_e15fb.h linuxppc_2_4_devel-local/drivers/video/ibm_e15fb.h
--- linuxppc_2_4_devel/drivers/video/ibm_e15fb.h	Thu Jan  1 01:00:00 1970
+++ linuxppc_2_4_devel-local/drivers/video/ibm_e15fb.h	Mon Jun 10 19:37:48 2002
@@ -0,0 +1,62 @@
+/*
+ * linux/drivers/video/ibm_e15fb.h
+ *
+ * Copyright (C) 2000 David Monro
+ *
+ */
+#ifndef IBM_E15FB_H
+#define IBM_E15FB_H
+
+struct ibm_e15fb_par {
+    /*
+     *  The hardware specific data in this structure uniquely defines a video
+     *  mode.
+     */
+
+    long freq;
+    int clock_m, clock_n1, clock_n2;
+    int bpp;
+    int syncflags;
+
+    long xres;
+    long xfrontporch;
+    long xsync;
+    long xbackporch;
+
+    long yres;
+    long yfrontporch;
+    long ysync;
+    long ybackporch;
+};
+
+struct ibm_e15fb_info {
+    struct fb_info_gen gen;
+
+    u32 fb_virt_membase;
+    u32 fb_phys_membase;
+    
+    struct ibm_e15fb_par current_par;
+};
+
+#define SDAC_REG04 (0x3C8)
+#define SDAC_REG05 (0x3C9)
+#define SDAC_REG06 (0x3C6)
+#define SDAC_REG07 (0x3C7)
+
+#define SDAC_MAXNONMUXCLOCK (67500)
+#define SDAC_MIN_M (3)
+#define SDAC_MAX_M (129)
+#define SDAC_MIN_N1 (3)
+#define SDAC_MAX_N1 (33)
+#define SDAC_MIN_N2 (0)
+#define SDAC_MAX_N2 (3)
+
+#define SDAC_MEMCLK (60000) /* This should work... */
+
+#define SDAC_MAX_VCO	(270000)
+#define SDAC_MIN_VCO	(60000)
+#define SDAC_REFCLK	(14318)
+
+#define SDAC_MAXERR (200) /* = 0.5% */
+
+#endif
diff -urN -X /home/leigh/.diffex linuxppc_2_4_devel/drivers/video/vgaregs.h linuxppc_2_4_devel-local/drivers/video/vgaregs.h
--- linuxppc_2_4_devel/drivers/video/vgaregs.h	Thu Jan  1 01:00:00 1970
+++ linuxppc_2_4_devel-local/drivers/video/vgaregs.h	Mon Jun 10 19:37:48 2002
@@ -0,0 +1,441 @@
+/*
+ * linux/include/video/vga.h -- standard VGA chipset interaction
+ *
+ * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * 
+ * Copyright history from vga16fb.c:
+ *	Copyright 1999 Ben Pfaff and Petr Vandrovec
+ *	Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm
+ *	Based on VESA framebuffer (c) 1998 Gerd Knorr
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of this
+ * archive for more details.  
+ *
+ */
+
+#ifndef __linux_video_vgaregs_h__
+#define __linux_video_vgaregs_h__
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+
+/* Some of the code below is taken from SVGAlib.  The original,
+   unmodified copyright notice for that code is below. */
+/* VGAlib version 1.2 - (c) 1993 Tommy Frandsen                    */
+/*                                                                 */
+/* This library is free software; you can redistribute it and/or   */
+/* modify it without any restrictions. This library is distributed */
+/* in the hope that it will be useful, but without any warranty.   */
+
+/* Multi-chipset support Copyright 1993 Harm Hanemaayer */
+/* partially copyrighted (C) 1993 by Hartmut Schirmer */
+
+/* VGA data register ports */
+#define VGA_CRT_DC  	0x3D5	/* CRT Controller Data Register - color emulation */
+#define VGA_CRT_DM  	0x3B5	/* CRT Controller Data Register - mono emulation */
+#define VGA_ATT_R   	0x3C1	/* Attribute Controller Data Read Register */
+#define VGA_ATT_W   	0x3C0	/* Attribute Controller Data Write Register */
+#define VGA_GFX_D   	0x3CF	/* Graphics Controller Data Register */
+#define VGA_SEQ_D   	0x3C5	/* Sequencer Data Register */
+#define VGA_MIS_R   	0x3CC	/* Misc Output Read Register */
+#define VGA_MIS_W   	0x3C2	/* Misc Output Write Register */
+#define VGA_FTC_R	0x3CA	/* Feature Control Read Register */
+#define VGA_IS1_RC  	0x3DA	/* Input Status Register 1 - color emulation */
+#define VGA_IS1_RM  	0x3BA	/* Input Status Register 1 - mono emulation */
+#define VGA_PEL_D   	0x3C9	/* PEL Data Register */
+#define VGA_PEL_MSK 	0x3C6	/* PEL mask register */
+
+/* EGA-specific registers */
+#define EGA_GFX_E0	0x3CC	/* Graphics enable processor 0 */
+#define EGA_GFX_E1	0x3CA	/* Graphics enable processor 1 */
+
+/* VGA index register ports */
+#define VGA_CRT_IC  	0x3D4	/* CRT Controller Index - color emulation */
+#define VGA_CRT_IM  	0x3B4	/* CRT Controller Index - mono emulation */
+#define VGA_ATT_IW  	0x3C0	/* Attribute Controller Index & Data Write Register */
+#define VGA_GFX_I   	0x3CE	/* Graphics Controller Index */
+#define VGA_SEQ_I   	0x3C4	/* Sequencer Index */
+#define VGA_PEL_IW  	0x3C8	/* PEL Write Index */
+#define VGA_PEL_IR  	0x3C7	/* PEL Read Index */
+
+/* standard VGA indexes max counts */
+#define VGA_CRT_C   	0x19	/* Number of CRT Controller Registers */
+#define VGA_ATT_C   	0x15	/* Number of Attribute Controller Registers */
+#define VGA_GFX_C   	0x09	/* Number of Graphics Controller Registers */
+#define VGA_SEQ_C   	0x05	/* Number of Sequencer Registers */
+#define VGA_MIS_C   	0x01	/* Number of Misc Output Register */
+
+/* VGA misc register bit masks */
+#define VGA_MIS_COLOR		0x01
+#define VGA_MIS_ENB_MEM_ACCESS	0x02
+#define VGA_MIS_DCLK_28322_720	0x04
+#define VGA_MIS_ENB_PLL_LOAD	(0x04 | 0x08)
+#define VGA_MIS_SEL_HIGH_PAGE	0x20
+
+/* VGA CRT controller register indices */
+#define VGA_CRTC_H_TOTAL	0
+#define VGA_CRTC_H_DISP		1
+#define VGA_CRTC_H_BLANK_START	2
+#define VGA_CRTC_H_BLANK_END	3
+#define VGA_CRTC_H_SYNC_START	4
+#define VGA_CRTC_H_SYNC_END	5
+#define VGA_CRTC_V_TOTAL	6
+#define VGA_CRTC_OVERFLOW	7
+#define VGA_CRTC_PRESET_ROW	8
+#define VGA_CRTC_MAX_SCAN	9
+#define VGA_CRTC_CURSOR_START	0x0A
+#define VGA_CRTC_CURSOR_END	0x0B
+#define VGA_CRTC_START_HI	0x0C
+#define VGA_CRTC_START_LO	0x0D
+#define VGA_CRTC_CURSOR_HI	0x0E
+#define VGA_CRTC_CURSOR_LO	0x0F
+#define VGA_CRTC_V_SYNC_START	0x10
+#define VGA_CRTC_V_SYNC_END	0x11
+#define VGA_CRTC_V_DISP_END	0x12
+#define VGA_CRTC_OFFSET		0x13
+#define VGA_CRTC_UNDERLINE	0x14
+#define VGA_CRTC_V_BLANK_START	0x15
+#define VGA_CRTC_V_BLANK_END	0x16
+#define VGA_CRTC_MODE		0x17
+#define VGA_CRTC_LINE_COMPARE	0x18
+#define VGA_CRTC_REGS		VGA_CRT_C
+
+/* VGA CRT controller bit masks */
+#define VGA_CR11_LOCK_CR0_CR7	0x80 /* lock writes to CR0 - CR7 */
+#define VGA_CR17_H_V_SIGNALS_ENABLED 0x80
+
+/* VGA attribute controller register indices */
+#define VGA_ATC_PALETTE0	0x00
+#define VGA_ATC_PALETTE1	0x01
+#define VGA_ATC_PALETTE2	0x02
+#define VGA_ATC_PALETTE3	0x03
+#define VGA_ATC_PALETTE4	0x04
+#define VGA_ATC_PALETTE5	0x05
+#define VGA_ATC_PALETTE6	0x06
+#define VGA_ATC_PALETTE7	0x07
+#define VGA_ATC_PALETTE8	0x08
+#define VGA_ATC_PALETTE9	0x09
+#define VGA_ATC_PALETTEA	0x0A
+#define VGA_ATC_PALETTEB	0x0B
+#define VGA_ATC_PALETTEC	0x0C
+#define VGA_ATC_PALETTED	0x0D
+#define VGA_ATC_PALETTEE	0x0E
+#define VGA_ATC_PALETTEF	0x0F
+#define VGA_ATC_MODE		0x10
+#define VGA_ATC_OVERSCAN	0x11
+#define VGA_ATC_PLANE_ENABLE	0x12
+#define VGA_ATC_PEL		0x13
+#define VGA_ATC_COLOR_PAGE	0x14
+
+#define VGA_AR_ENABLE_DISPLAY	0x20
+
+/* VGA sequencer register indices */
+#define VGA_SEQ_RESET		0x00
+#define VGA_SEQ_CLOCK_MODE	0x01
+#define VGA_SEQ_PLANE_WRITE	0x02
+#define VGA_SEQ_CHARACTER_MAP	0x03
+#define VGA_SEQ_MEMORY_MODE	0x04
+
+/* VGA sequencer register bit masks */
+#define VGA_SR01_CHAR_CLK_8DOTS	0x01 /* bit 0: character clocks 8 dots wide are generated */
+#define VGA_SR01_SCREEN_OFF	0x20 /* bit 5: Screen is off */
+#define VGA_SR02_ALL_PLANES	0x0F /* bits 3-0: enable access to all planes */
+#define VGA_SR04_EXT_MEM	0x02 /* bit 1: allows complete mem access to 256K */
+#define VGA_SR04_SEQ_MODE	0x04 /* bit 2: directs system to use a sequential addressing mode */
+#define VGA_SR04_CHN_4M		0x08 /* bit 3: selects modulo 4 addressing for CPU access to display memory */
+
+/* VGA graphics controller register indices */
+#define VGA_GFX_SR_VALUE	0x00
+#define VGA_GFX_SR_ENABLE	0x01
+#define VGA_GFX_COMPARE_VALUE	0x02
+#define VGA_GFX_DATA_ROTATE	0x03
+#define VGA_GFX_PLANE_READ	0x04
+#define VGA_GFX_MODE		0x05
+#define VGA_GFX_MISC		0x06
+#define VGA_GFX_COMPARE_MASK	0x07
+#define VGA_GFX_BIT_MASK	0x08
+
+/* VGA graphics controller bit masks */
+#define VGA_GR06_GRAPHICS_MODE	0x01
+
+/* macro for composing an 8-bit VGA register index and value
+ * into a single 16-bit quantity */
+#define VGA_OUT16VAL(v, r)       (((v) << 8) | (r))
+
+/* decide whether we should enable the faster 16-bit VGA register writes */
+#ifdef __LITTLE_ENDIAN
+#define VGA_OUTW_WRITE
+#endif
+
+
+/*
+ * generic VGA port read/write
+ */
+ 
+extern inline unsigned char vga_io_r (unsigned short port)
+{
+	return inb (port);
+}
+
+extern inline void vga_io_w (unsigned short port, unsigned char val)
+{
+	outb (val, port);
+}
+
+extern inline void vga_io_w_fast (unsigned short port, unsigned char reg,
+				  unsigned char val)
+{
+	outw (VGA_OUT16VAL (val, reg), port);
+}
+
+extern inline unsigned char vga_mm_r (caddr_t regbase, unsigned short port)
+{
+	return readb (regbase + port);
+}
+
+extern inline void vga_mm_w (caddr_t regbase, unsigned short port, unsigned char val)
+{
+	writeb (val, regbase + port);
+}
+
+extern inline void vga_mm_w_fast (caddr_t regbase, unsigned short port,
+				  unsigned char reg, unsigned char val)
+{
+	writew (VGA_OUT16VAL (val, reg), regbase + port);
+}
+
+extern inline unsigned char vga_r (caddr_t regbase, unsigned short port)
+{
+	if (regbase)
+		return vga_mm_r (regbase, port);
+	else
+		return vga_io_r (port);
+}
+
+extern inline void vga_w (caddr_t regbase, unsigned short port, unsigned char val)
+{
+	if (regbase)
+		vga_mm_w (regbase, port, val);
+	else
+		vga_io_w (port, val);
+}
+
+
+extern inline void vga_w_fast (caddr_t regbase, unsigned short port,
+			       unsigned char reg, unsigned char val)
+{
+	if (regbase)
+		vga_mm_w_fast (regbase, port, reg, val);
+	else
+		vga_io_w_fast (port, reg, val);
+}
+
+
+/*
+ * VGA CRTC register read/write
+ */
+ 
+extern inline unsigned char vga_rcrt (caddr_t regbase, unsigned char reg)
+{
+        vga_w (regbase, VGA_CRT_IC, reg);
+        return vga_r (regbase, VGA_CRT_DC);
+}
+
+extern inline void vga_wcrt (caddr_t regbase, unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_w_fast (regbase, VGA_CRT_IC, reg, val);
+#else
+        vga_w (regbase, VGA_CRT_IC, reg);
+        vga_w (regbase, VGA_CRT_DC, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+extern inline unsigned char vga_io_rcrt (unsigned char reg)
+{
+        vga_io_w (VGA_CRT_IC, reg);
+        return vga_io_r (VGA_CRT_DC);
+}
+
+extern inline void vga_io_wcrt (unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_io_w_fast (VGA_CRT_IC, reg, val);
+#else
+        vga_io_w (VGA_CRT_IC, reg);
+        vga_io_w (VGA_CRT_DC, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+extern inline unsigned char vga_mm_rcrt (caddr_t regbase, unsigned char reg)
+{
+        vga_mm_w (regbase, VGA_CRT_IC, reg);
+        return vga_mm_r (regbase, VGA_CRT_DC);
+}
+
+extern inline void vga_mm_wcrt (caddr_t regbase, unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_mm_w_fast (regbase, VGA_CRT_IC, reg, val);
+#else
+        vga_mm_w (regbase, VGA_CRT_IC, reg);
+        vga_mm_w (regbase, VGA_CRT_DC, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+
+/*
+ * VGA sequencer register read/write
+ */
+ 
+extern inline unsigned char vga_rseq (caddr_t regbase, unsigned char reg)
+{
+        vga_w (regbase, VGA_SEQ_I, reg);
+        return vga_r (regbase, VGA_SEQ_D);
+}
+
+extern inline void vga_wseq (caddr_t regbase, unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_w_fast (regbase, VGA_SEQ_I, reg, val);
+#else
+        vga_w (regbase, VGA_SEQ_I, reg);
+        vga_w (regbase, VGA_SEQ_D, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+extern inline unsigned char vga_io_rseq (unsigned char reg)
+{
+        vga_io_w (VGA_SEQ_I, reg);
+        return vga_io_r (VGA_SEQ_D);
+}
+
+extern inline void vga_io_wseq (unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_io_w_fast (VGA_SEQ_I, reg, val);
+#else
+        vga_io_w (VGA_SEQ_I, reg);
+        vga_io_w (VGA_SEQ_D, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+extern inline unsigned char vga_mm_rseq (caddr_t regbase, unsigned char reg)
+{
+        vga_mm_w (regbase, VGA_SEQ_I, reg);
+        return vga_mm_r (regbase, VGA_SEQ_D);
+}
+
+extern inline void vga_mm_wseq (caddr_t regbase, unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_mm_w_fast (regbase, VGA_SEQ_I, reg, val);
+#else
+        vga_mm_w (regbase, VGA_SEQ_I, reg);
+        vga_mm_w (regbase, VGA_SEQ_D, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+
+
+/*
+ * VGA graphics controller register read/write
+ */
+ 
+extern inline unsigned char vga_rgfx (caddr_t regbase, unsigned char reg)
+{
+        vga_w (regbase, VGA_GFX_I, reg);
+        return vga_r (regbase, VGA_GFX_D);
+}
+
+extern inline void vga_wgfx (caddr_t regbase, unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_w_fast (regbase, VGA_GFX_I, reg, val);
+#else
+        vga_w (regbase, VGA_GFX_I, reg);
+        vga_w (regbase, VGA_GFX_D, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+extern inline unsigned char vga_io_rgfx (unsigned char reg)
+{
+        vga_io_w (VGA_GFX_I, reg);
+        return vga_io_r (VGA_GFX_D);
+}
+
+extern inline void vga_io_wgfx (unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_io_w_fast (VGA_GFX_I, reg, val);
+#else
+        vga_io_w (VGA_GFX_I, reg);
+        vga_io_w (VGA_GFX_D, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+extern inline unsigned char vga_mm_rgfx (caddr_t regbase, unsigned char reg)
+{
+        vga_mm_w (regbase, VGA_GFX_I, reg);
+        return vga_mm_r (regbase, VGA_GFX_D);
+}
+
+extern inline void vga_mm_wgfx (caddr_t regbase, unsigned char reg, unsigned char val)
+{
+#ifdef VGA_OUTW_WRITE
+	vga_mm_w_fast (regbase, VGA_GFX_I, reg, val);
+#else
+        vga_mm_w (regbase, VGA_GFX_I, reg);
+        vga_mm_w (regbase, VGA_GFX_D, val);
+#endif /* VGA_OUTW_WRITE */
+}
+
+
+/*
+ * VGA attribute controller register read/write
+ */
+ 
+extern inline unsigned char vga_rattr (caddr_t regbase, unsigned char reg)
+{
+        vga_w (regbase, VGA_ATT_IW, reg);
+        return vga_r (regbase, VGA_ATT_R);
+}
+
+extern inline void vga_wattr (caddr_t regbase, unsigned char reg, unsigned char val)
+{
+        vga_w (regbase, VGA_ATT_IW, reg);
+        vga_w (regbase, VGA_ATT_W, val);
+}
+
+extern inline unsigned char vga_io_rattr (unsigned char reg)
+{
+        vga_io_w (VGA_ATT_IW, reg);
+        return vga_io_r (VGA_ATT_R);
+}
+
+extern inline void vga_io_wattr (unsigned char reg, unsigned char val)
+{
+        vga_io_w (VGA_ATT_IW, reg);
+        vga_io_w (VGA_ATT_W, val);
+}
+
+extern inline unsigned char vga_mm_rattr (caddr_t regbase, unsigned char reg)
+{
+        vga_mm_w (regbase, VGA_ATT_IW, reg);
+        return vga_mm_r (regbase, VGA_ATT_R);
+}
+
+extern inline void vga_mm_wattr (caddr_t regbase, unsigned char reg, unsigned char val)
+{
+        vga_mm_w (regbase, VGA_ATT_IW, reg);
+        vga_mm_w (regbase, VGA_ATT_W, val);
+}
+
+
+
+
+#endif /* __linux_video_vga_h__ */

