Summary:
 FB driver modules
  - add support for PC-9800 standard video card
  - add support multi-byte charactors. (2bytes japanese kanji only, now)
diffstat:
 drivers/video/Config.in   |    4 
 drivers/video/Makefile    |    4 
 drivers/video/egcfb.c     |  654 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/video/fbcon-egc.c |  681 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/video/fbcon.c     |  461 ++++++++++++++++++++++++++++++-
 drivers/video/fbmem.c     |   60 ++++
 include/video/fbcon-egc.h |   32 ++
 7 files changed, 1887 insertions(+), 9 deletions(-)
patch:
diff -urN linux/drivers/video/Config.in linux98/drivers/video/Config.in
--- linux/drivers/video/Config.in	Wed Jul 17 08:49:34 2002
+++ linux98/drivers/video/Config.in	Fri Jul 19 16:09:49 2002
@@ -95,10 +95,14 @@
       tristate '  TGA framebuffer support' CONFIG_FB_TGA
    fi
    if [ "$CONFIG_X86" = "y" ]; then
+     if [ "$CONFIG_PC9800" != "y" ]; then
       bool '  VESA VGA graphics console' CONFIG_FB_VESA
       tristate '  VGA 16-color graphics console' CONFIG_FB_VGA16
       tristate '  Hercules mono graphics console (EXPERIMENTAL)' CONFIG_FB_HGA
       define_bool CONFIG_VIDEO_SELECT y
+     else
+      tristate '  EGC 16-color graphics console' CONFIG_FB_EGC
+     fi
    fi
    if [ "$CONFIG_VISWS" = "y" ]; then
       tristate '  SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW
diff -urN linux/drivers/video/Makefile linux98/drivers/video/Makefile
--- linux/drivers/video/Makefile	Tue Oct  8 10:56:16 2002
+++ linux98/drivers/video/Makefile	Tue Oct  8 11:01:41 2002
@@ -10,7 +10,7 @@
 		   fbcon-iplan2p2.o fbcon-iplan2p4.o fbgen.o \
 		   fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \
 		   fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \
-		   fbcon-cfb8.o fbcon-mfb.o fbcon-hga.o
+		   fbcon-cfb8.o fbcon-mfb.o fbcon-egc.o fbcon-hga.o
 
 # Each configuration option enables a list of files.
 
@@ -19,6 +19,7 @@
 obj-$(CONFIG_PROM_CONSOLE)        += promcon.o promcon_tbl.o
 obj-$(CONFIG_STI_CONSOLE)         += sticon.o sticon-bmode.o sticore.o
 obj-$(CONFIG_VGA_CONSOLE)         += vgacon.o
+obj-$(CONFIG_GDC_CONSOLE)         += gdccon.o
 obj-$(CONFIG_MDA_CONSOLE)         += mdacon.o
 
 obj-$(CONFIG_FONT_SUN8x16)        += font_sun8x16.o
@@ -69,6 +70,7 @@
 obj-$(CONFIG_FB_TGA)              += tgafb.o
 obj-$(CONFIG_FB_VESA)             += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o 
 obj-$(CONFIG_FB_VGA16)            += vga16fb.o fbcon-vga-planes.o
+obj-$(CONFIG_FB_EGC)              += egcfb.o fbcon-egc.o
 obj-$(CONFIG_FB_VIRGE)            += virgefb.o
 obj-$(CONFIG_FB_G364)             += g364fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_FM2)              += fm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
diff -urN linux/drivers/video/egcfb.c linux98/drivers/video/egcfb.c
--- linux/drivers/video/egcfb.c	Thu Jan  1 09:00:00 1970
+++ linux98/drivers/video/egcfb.c	Tue Sep  3 16:27:04 2002
@@ -0,0 +1,654 @@
+/*
+ * linux/drivers/video/egcfb.c -- EGC/GRCG framebuffer
+ *
+ * Copyright 1999 Satoshi YAMADA <slakichi@kmc.kyoto-u.ac.jp>
+ *
+ * Based on VGA framebuffer (C) 1999 Ben Pfaff <pfaffben@debian.org> ,
+ *				     Petr Vandrovec <VANDROVE@vc.cvut.cz>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of this
+ * archive for more details. 
+ */
+
+#include <linux/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/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-egc.h>
+
+/* plane 0,1,2 */
+#define EGC_RGB_FB_PHYS 0xA8000
+#define EGC_RGB_FB_PHYS_LEN 0x18000
+/* plane 3 */
+#define EGC_E_FB_PHYS 0xE0000
+#define EGC_E_FB_PHYS_LEN 0x8000
+/* total (fix-info returns these value, but these are INVALID value!) */
+#define EGC_FB_PHYS 0xA8000
+#define EGC_FB_PHYS_LEN 0x20000
+
+#define EGCIO_GDC_CMD		0xa2
+#define EGCIO_GDC_PARAM		0xa0
+#define EGCIO_PL_NUM		0xa8
+#define EGCIO_PL_GREEN		0xaa
+#define EGCIO_PL_RED		0xac
+#define EGCIO_PL_BLUE		0xae
+#define EGCIO_SYNCCTRL		0x9a2
+
+#define EGCMEM_ISEGC		0x54d
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * card parameters
+ */
+
+static struct fb_info	fb_info;	/* framebuffer info */
+static char *video_vbase[2];		/* VRAM base address in virtual */
+static int hasEGC;			/* This matchine has EGC?(1/0) */
+static int palette_blanked;		/* Blanked by Palette control */
+static int sync_blanked;		/* Blanked by APM control */
+
+
+/* --------------------------------------------------------------------- */
+
+/* default GDC parameters */
+#define EGC_FB_PIXCLOCK	 39708	/* 1/((margins+hsync_len+xres[pix])*(hsync[Hz])) */
+#define EGC_FB_MARGIN_LE 32	/* SYNC HBP 512>= ([P5(b5-b0)]+1)*8 >= 24 */
+#define EGC_FB_MARGIN_R	 32	/* SYNC HFP 512>= ([P4(b7-b2)]+1)*8 >= 16 */
+#define EGC_FB_MARGIN_U	 37	/* SYNC VBP 63 >= P8(b7-b2) >= 1 */
+#define EGC_FB_MARGIN_LO 2	/* SYNC VFP 63 >= P6(b5-b0) >= 1 */
+#define EGC_FB_HSYNC	 96	/* SYNC HS  512>= ([P3(b5-b0)]+1)*8 ,>=32 */
+#define EGC_FB_VSYNC	 2	/* SYNC VS  31 >= [P4(b1-b0)P3(b7-b5)] , >=1 */
+
+/*
+
+4+80+4+12+2=98*8=784pixels,70Hz
+
+37+400+2+2=441lines,31.48Hz
+
+*/
+
+static struct fb_var_screeninfo egcfb_defined = {
+	.xres		= 640,
+	.yres		= 400,
+	.xres_virtual	= 640,
+	.yres_virtual	= 400,
+	.xoffset	= 0,		/* virtual -> visible no offset */
+	.yoffset	= 0,
+	.bits_per_pixel	= 4,
+	.grayscale	= 0,		/* not greyscale but color */
+	.red		= {0, 0, 0},
+	.green		= {0, 0, 0},
+	.blue		= {0, 0, 0},
+	.transp		= {0, 0, 0},	/* transparency */
+	.nonstd		= 0,		/* standard pixel format */
+	.activate	= FB_ACTIVATE_NOW,
+	.height		= -1,
+	.width		= -1,
+	.accel_flags	= 0,
+	.pixclock	= EGC_FB_PIXCLOCK,
+	.left_margin	= EGC_FB_MARGIN_LE,
+	.right_margin	= EGC_FB_MARGIN_R,
+	.upper_margin	= EGC_FB_MARGIN_U,
+	.lower_margin	= EGC_FB_MARGIN_LO,
+	.hsync_len	= EGC_FB_HSYNC,
+	.vsync_len	= EGC_FB_VSYNC,
+	.sync		= 0,		/* No sync info */
+	.vmode = FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo egcfb_fix __initdata = {
+	.id		= "egc",
+	.smem_start	= EGC_FB_PHYS,
+	.smem_len	= EGC_FB_PHYS_LEN,
+	.type		= FB_TYPE_VGA_PLANES,
+	.visual		= FB_VISUAL_PSEUDOCOLOR,
+	.xpanstep	= 8,
+	.ypanstep	= 1,
+	.ywrapstep	= 0,
+	.line_length	= 80,
+	.accel		= FB_ACCEL_NONE,
+};
+
+static struct display default_display;
+static struct {
+	u_short blue, green, red, transp;
+} palette[16];
+
+static spinlock_t egcfb_lock = SPIN_LOCK_UNLOCKED;
+
+/* --------------------------------------------------------------------- */
+
+static void egcfb_set_display(int con_num, struct fb_info *info)
+{
+	struct display *display;
+
+	if (con_num < 0)
+		display = &default_display;
+	else
+		display = fb_display + con_num;
+
+	display->can_soft_blank = 1;
+	display->inverse = 0;
+	display->dispsw = &fbcon_egc;
+	display->fb_info = info;
+	display->next_line = info->fix.line_length;
+	display->scrollmode = SCROLL_YREDRAW;
+}
+
+static int egcfb_check_var(const struct fb_var_screeninfo *var,
+			   const struct fb_info *info)
+{
+	if(var->xres != 640 || var->xres_virtual != 640)
+		return -EINVAL;
+	if(var->yres != 400 || var->yres_virtual != 400)
+		return -EINVAL;
+	if(var->xoffset != 0 || var->yoffset != 0)
+		return -EINVAL;
+	if(var->bits_per_pixel != 4)
+		return -EINVAL;
+	return 0;
+}
+
+static void egcfb_set_defaultvar(struct fb_var_screeninfo *var)
+{
+	unsigned long flags;
+
+	var->xres=var->xres_virtual=640;
+	var->yres=var->yres_virtual=400;
+	var->xoffset=var->yoffset=0;
+	var->bits_per_pixel=4;
+	var->grayscale=0;
+	var->red.length=var->green.length=var->blue.length=4;
+	var->red.offset=var->green.offset=var->blue.offset=0;
+	var->transp.length=var->transp.offset=0;
+	var->nonstd=0;
+	var->height=var->width=-1;
+	var->accel_flags=0;
+	var->left_margin=EGC_FB_MARGIN_LE;
+	var->right_margin=EGC_FB_MARGIN_R;
+	var->upper_margin=EGC_FB_MARGIN_U;
+	var->lower_margin=EGC_FB_MARGIN_LO;
+	var->hsync_len=EGC_FB_HSYNC;
+	var->vsync_len=EGC_FB_VSYNC;
+	var->sync=0;
+	var->vmode=FB_VMODE_NONINTERLACED;
+
+	spin_lock_irqsave(&egcfb_lock, flags);
+	outb_p(0x47,0xa2);
+	outb_p(80,0xa0);	/* pitch command */
+	outb_p(0x01,0x6a);
+	outb_p(0x00,0xa4);	/* show bank:0 */
+	outb_p(0x00,0xa6);	/* write bank:0 */
+	outb_p(0x0d,0xa2); /* Show Graphics */
+	outb_p(0x0c,0x62); /* Hide Text */
+	spin_unlock_irqrestore(&egcfb_lock, flags);
+}
+
+static int egcfb_set_varinfo(struct fb_var_screeninfo *var, int con_num,
+			       struct fb_info *info)
+{
+#if 0
+	struct display *display;
+#endif
+	int retval;
+
+#if 0
+	if (con < 0)
+		display = info->disp;
+	else
+		display = fb_display + con;
+#endif
+	retval = egcfb_check_var(var, info);
+	if (retval != 0)
+		return retval;
+	egcfb_set_defaultvar(var);
+	
+	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
+		return 0;
+
+#if 0
+	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+	/* Nothing to do. */
+	}
+#endif
+
+	return 0;
+}
+
+static int egcfb_get_palette(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.
+	 *  Return != 0 for invalid regno.
+	 */
+
+	if (regno >= 16)
+		return 1;
+
+	*red   = palette[regno].red;
+	*green = palette[regno].green;
+	*blue  = palette[regno].blue;
+	*transp = 0;
+	return 0;
+}
+
+static __inline__ void egcfb_do_set_palette(int regno, unsigned red,
+						unsigned green, unsigned blue)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&egcfb_lock, flags);
+	outb_p(regno, EGCIO_PL_NUM);
+	outb_p(green >> 12, EGCIO_PL_GREEN);
+	outb_p(red   >> 12, EGCIO_PL_RED);
+	outb_p(blue  >> 12, EGCIO_PL_BLUE);
+	spin_unlock_irqrestore(&egcfb_lock, flags);
+}
+
+
+
+static int egcfb_set_palette(unsigned regno, unsigned red, unsigned green,
+			  unsigned blue, unsigned transp,
+			  struct fb_info *info)
+{
+	int gray;
+
+	if (regno >= 16)
+		return 1;
+
+	palette[regno].red   = red;
+	palette[regno].green = green;
+	palette[regno].blue  = blue;
+	
+	if (fb_info.currcon < 0)
+		gray = default_display.var.grayscale;
+	else
+		gray = fb_display[fb_info.currcon].var.grayscale;
+
+	if (gray)
+		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+
+	egcfb_do_set_palette(regno, red, green, blue);
+	
+	return 0;
+}
+
+static void egcfb_set_palette_all(int con_num, struct fb_info *info)
+{
+	if (con_num != fb_info.currcon)
+		return;
+
+	if (fb_display[con_num].cmap.len)
+		fb_set_cmap(&fb_display[con_num].cmap, 1, info);
+	else
+		fb_set_cmap(fb_default_cmap(16), 1, info);
+}
+
+
+static int egcfb_get_colormap(struct fb_cmap *cmap, int kspc, int con_num,
+			    struct fb_info *info)
+{
+	if (con_num != fb_info.currcon)
+		return fb_get_cmap(cmap, kspc, egcfb_get_palette, info);
+	else if (fb_display[con_num].cmap.len)
+		fb_copy_cmap(&fb_display[con_num].cmap, cmap, kspc ? 0 : 2);
+	else
+		fb_copy_cmap(fb_default_cmap(16), cmap, kspc ? 0 : 2);
+
+	return 0;
+}
+
+static int egcfb_set_colormap(struct fb_cmap *cmap, int kspc, int con_num,
+			   struct fb_info *info)
+{
+	int err;
+
+	if (!fb_display[con_num].cmap.len) {	/* no colormap allocated? */
+		err = fb_alloc_cmap(&fb_display[con_num].cmap, 16, 0);
+		if (err)
+			return err;
+	}
+
+	if (con_num == fb_info.currcon) {
+		int retval = fb_set_cmap(cmap, kspc, info);
+		//if( retval == 0 )
+		//	fb_copy_cmap(cmap, &fb_display[fb_info.currcon].cmap, kspc ? 0 : 1);
+		return retval;
+	} else
+		fb_copy_cmap(cmap, &fb_display[con_num].cmap, kspc ? 0 : 1);
+
+	return 0;
+}
+
+static int egcfb_pan_display(struct fb_var_screeninfo *var, int con_num,
+			       struct fb_info *info) 
+{
+	if (var->xoffset + fb_display[con_num].var.xres
+			> fb_display[con_num].var.xres_virtual
+	    || var->yoffset + fb_display[con_num].var.yres
+			> fb_display[con_num].var.yres_virtual)
+		return -EINVAL;
+
+	/* must be xoffset=yoffset=0, so nothing to do. */
+	fb_display[con_num].var.xoffset = var->xoffset;
+	fb_display[con_num].var.yoffset = var->yoffset;
+	fb_display[con_num].var.vmode &= ~FB_VMODE_YWRAP;
+	return 0;
+}
+
+static int egcfb_mmap(struct fb_info *info, struct file *file,
+		      struct vm_area_struct * vma)
+{
+	/* based on fbmem.c - Copyright (C) 1994 Martin Schaller */
+	unsigned long start, len, off;
+	unsigned long vm_end, vm_start;
+	pgprot_t vm_prot;
+
+	off	 = vma->vm_pgoff << PAGE_SHIFT;
+	vm_start = vma->vm_start;
+	vm_end	 = vma->vm_end;
+
+	start = EGC_FB_PHYS;
+	len   = (start & ~PAGE_MASK) + EGC_FB_PHYS_LEN;
+	start &= PAGE_MASK;
+	len = (len + ~PAGE_MASK) & PAGE_MASK;
+
+	if (vm_end - vm_start + off > len)
+		return -EINVAL;
+
+	if (boot_cpu_data.x86 > 3)
+		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+
+	vm_prot = vma->vm_page_prot;
+
+	/* This is fake ;-) */
+	vma->vm_pgoff = ( off + start ) >> PAGE_SHIFT;
+
+	/* Plane 0,1,2 */
+	
+	start = EGC_RGB_FB_PHYS;
+	len   = (start & ~PAGE_MASK) + EGC_RGB_FB_PHYS_LEN;
+	start &= PAGE_MASK;
+	len = (len + ~PAGE_MASK) & PAGE_MASK;
+
+	if(off < len) {
+		if ((vm_end - vm_start + off) > len)
+			vm_end = (len - off) + vm_start;
+
+		if (io_remap_page_range(vma, vm_start, start + off,
+				     vm_end - vm_start, vma->vm_page_prot))
+			return -EAGAIN;
+
+		/* restore */
+		vm_end = vma->vm_end;
+	}
+	
+	/* Plane 3 (Extended) */
+	
+	start = EGC_E_FB_PHYS;
+	len   = (start & ~PAGE_MASK) + EGC_E_FB_PHYS_LEN;
+	start &= PAGE_MASK;
+	len = (len + ~PAGE_MASK) & PAGE_MASK;
+	
+	if (vm_end - vm_start + off > EGC_RGB_FB_PHYS_LEN) {
+		if (off < EGC_RGB_FB_PHYS_LEN) {
+			vm_start += (EGC_RGB_FB_PHYS_LEN - off);
+			off = 0;
+		} else
+			off -= EGC_RGB_FB_PHYS_LEN;
+
+		if ((vm_end - vm_start + off) > len)
+			/* mustn't be occured ... */
+			return -EINVAL;
+
+		if (io_remap_page_range(vma, vm_start, start + off,
+				     vm_end - vm_start, vma->vm_page_prot))
+			/* FIXME: don't re-remapped planes even if failed. */
+			return -EAGAIN;
+	}
+
+	return 0;
+
+}
+
+static void egcfb_sync_blank(struct fb_info *info, int mode)
+{
+	int sendcmd = 0;
+	unsigned long flags;
+
+	if ((mode & VESA_VSYNC_SUSPEND)
+			|| (sync_blanked & VESA_VSYNC_SUSPEND)) {
+		sync_blanked |= VESA_VSYNC_SUSPEND;
+		sendcmd |= 0x80;
+	}
+
+	if ((mode & VESA_HSYNC_SUSPEND)
+			|| (sync_blanked & VESA_HSYNC_SUSPEND)) {
+		sync_blanked |= VESA_HSYNC_SUSPEND;
+		sendcmd |= 0x40;
+	}
+
+	spin_lock_irqsave(&egcfb_lock, flags);
+	outb_p(sendcmd, EGCIO_SYNCCTRL);
+	spin_unlock_irqrestore(&egcfb_lock, flags);
+}
+
+static void egcfb_sync_unblank(struct fb_info *info)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&egcfb_lock, flags);
+	outb_p(0, EGCIO_SYNCCTRL);
+	spin_unlock_irqrestore(&egcfb_lock, flags);
+	sync_blanked = 0;
+}
+
+static void egcfb_pallete_blank(void)
+{
+	int i;
+	unsigned long flags;
+
+	for (i = 0; i < 16; i++) {
+		spin_lock_irqsave(&egcfb_lock, flags);
+		outb_p(i, EGCIO_PL_NUM);
+		outb_p(0, EGCIO_PL_GREEN);
+		outb_p(0, EGCIO_PL_RED);
+		outb_p(0, EGCIO_PL_BLUE);
+		spin_unlock_irqrestore(&egcfb_lock, flags);
+	}
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+static int egcfb_blank(int blank, struct fb_info *info)
+{
+	switch (blank) {
+	case 0:				/* Unblank */
+		if (sync_blanked) {
+			egcfb_sync_unblank(info);
+		}
+
+		if (palette_blanked) {
+			egcfb_set_palette_all(fb_info.currcon, info);
+			palette_blanked = 0;
+		}
+
+		break;
+
+	case 1:				/* blank */
+		egcfb_pallete_blank();
+		palette_blanked = 1;
+		break;
+
+	default:			/* VESA blanking */
+		egcfb_sync_blank(info, blank - 1);
+		break;
+	}
+
+	return 0;
+}
+
+static struct fb_ops egcfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_set_var	= egcfb_set_varinfo,
+	.fb_get_cmap	= egcfb_get_colormap,
+	.fb_set_cmap	= egcfb_set_colormap,
+	.fb_setcolreg	= egcfb_set_palette,
+	.fb_blank	= egcfb_blank,
+	.fb_pan_display	= egcfb_pan_display,
+	.fb_mmap	= egcfb_mmap,
+};
+
+int egcfb_setup(char *options)
+{
+	char *this_opt;
+	
+	fb_info.fontname[0] = '\0';
+	
+	if (!options || !*options)
+		return 0;
+	
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+
+		if (!strncmp(this_opt, "font:", 5))
+			strcpy(fb_info.fontname, this_opt + 5);
+	}
+
+	return 0;
+}
+
+/* on switching console ... */
+static int egcfb_switch(int con_num, struct fb_info *info)
+{
+	/* Do we have to save the colormap? */
+	if (fb_display[fb_info.currcon].cmap.len) {
+		fb_get_cmap(&fb_display[fb_info.currcon].cmap, 1,
+			    egcfb_get_palette, info);
+	}
+	
+	fb_info.currcon = con_num;
+	egcfb_set_defaultvar(&fb_display[con_num].var);
+	egcfb_set_display(con_num, info);
+	egcfb_set_palette_all(con_num, info);
+	return 1;
+}
+
+int __init egc_init(void)
+{
+	int i,j;
+
+	printk(KERN_DEBUG "egcfb: initializing\n");
+
+	if(!(isa_readb(0x054c) & (1 << 1))) {
+		printk(KERN_ERR "egcfb: this machine does not have GRCG, exiting\n");
+		return -EINVAL;
+	}
+
+	if(!(isa_readb(0x054c) & (1 << 2))) {
+		printk(KERN_ERR "egcfb: not 16-colors mode, exiting\n");
+		return -EINVAL;
+	}
+
+	if(!(isa_readb(0x054d) & (1 << 6))) {
+		printk(KERN_ERR "egcfb: this machine does not have EGC, exiting\n");
+		return -EINVAL;
+	}
+
+	video_vbase[0] = ioremap_nocache(EGC_RGB_FB_PHYS, EGC_RGB_FB_PHYS_LEN);
+	video_vbase[1] = ioremap_nocache(EGC_E_FB_PHYS, EGC_E_FB_PHYS_LEN);
+	printk(KERN_INFO "egcfb: mapped to 0x%p and 0x%p\n",
+	       video_vbase[0], video_vbase[1]);
+
+	hasEGC = (isa_readb(EGCMEM_ISEGC) & 0x40) ? 1 : 0;
+	palette_blanked = 0;
+	sync_blanked = 0;
+
+	egcfb_defined.red.length   = 4;
+	egcfb_defined.green.length = 4;
+	egcfb_defined.blue.length  = 4;
+	for (i = 0; i < 16; i++) {
+		j = color_table[i];
+		palette[i].red	 = default_red[j];
+		palette[i].green = default_grn[j];
+		palette[i].blue	 = default_blu[j];
+	}
+
+	default_display.var = egcfb_defined;
+
+	strcpy(fb_info.modename, egcfb_fix.id);
+	fb_info.changevar = NULL;
+	fb_info.node = NODEV;
+	fb_info.fbops = &egcfb_ops;
+	fb_info.var = egcfb_defined;
+	fb_info.fix = egcfb_fix;
+	fb_info.currcon = -1;
+	fb_info.screen_base = video_vbase[0];
+	fb_info.disp = &default_display;
+	fb_info.switch_con = egcfb_switch;
+	fb_info.updatevar = gen_update_var;
+	fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+	fb_alloc_cmap(&fb_info.cmap, 16, 0);
+	egcfb_set_display(-1, &fb_info);
+
+	isa_writeb(isa_readb(0x054C) | 0x80, 0x054C);
+
+	if (register_framebuffer(&fb_info) < 0)
+		return -EINVAL;
+
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       GET_FB_IDX(fb_info.node), fb_info.fix.id);
+
+	return 0;
+}
+
+#ifndef MODULE
+int __init egcfb_init(void)
+{
+    return egc_init();
+}
+
+#else /* MODULE */
+
+int init_module(void)
+{
+	return egc_init();
+}
+
+void cleanup_module(void)
+{
+	unregister_framebuffer(&fb_info);
+	iounmap(video_vbase[0]);
+	iounmap(video_vbase[1]);
+	__release_region(&ioport_resource, 0xa2, 1);
+}
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff -urN linux/drivers/video/fbcon-egc.c linux98/drivers/video/fbcon-egc.c
--- linux/drivers/video/fbcon-egc.c	Thu Jan  1 09:00:00 1970
+++ linux98/drivers/video/fbcon-egc.c	Mon Sep  2 17:03:11 2002
@@ -0,0 +1,681 @@
+/*
+ *  linux/drivers/video/fbcon-egc.c -- Low level frame buffer operations
+ *					      for EGC 
+ *
+ * Copyright (C) 1999,2000 Satoshi YAMADA <slakichi@kmc.kyoto-u.ac.jp>
+ *
+ * Based on fbcon-vga-planes.c (C) 1999 Ben Pfaff <pfaffben@debian.org>
+ *				    and Petr Vandrovec <VANDROVE@vc.cvut.cz>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of this
+ * archive for more details.	
+ */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_buffer.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-egc.h>
+
+#define EGCIO_EGC_R0 0x4a0
+#define EGCIO_EGC_R1 0x4a2
+#define EGCIO_EGC_R2 0x4a4
+#define EGCIO_EGC_R3 0x4a6
+#define EGCIO_EGC_R4 0x4a8
+#define EGCIO_EGC_R5 0x4aa
+#define EGCIO_EGC_R6 0x4ac
+#define EGCIO_EGC_R7 0x4ae
+
+#define EGCIO_KANJI_SETMODE	0x68
+#define EGCIO_KANJI_CG_LOW	0xa1
+#define EGCIO_KANJI_CG_HI	0xa3
+#define EGCIO_KANJI_CG_LR	0xa5
+
+#define EGCRAM_KANJI_CG		0xa4000
+
+#define KANJI_ACCESS		0x0b
+#define KANJI_NORMAL		0x0a
+
+#define NUM_CACHE		16 /* must be 2,4,8,16... */
+
+typedef struct facecache_t
+{
+	u8  isenable;
+	u16 chardata;
+	u8  left[16];
+	u8  right[16];
+} facecache;
+
+facecache fcache_kanji[NUM_CACHE];
+int       fcache_kanji_lastuse = -1;
+facecache fcache_ank[256];
+u8	  fcache_num;
+
+static spinlock_t fbcon_egc_lock = SPIN_LOCK_UNLOCKED;
+DECLARE_WAIT_QUEUE_HEAD(fbcon_egc_irq_wait);
+static int vsync_irq = 0;
+
+static u8 *egc_load_facedata(struct display *p, u16 data)
+{
+	int i;
+	int t;
+	u8 kanji_high = (u8)(data & 0x007f);
+	u16 rdata[32];
+//	unsigned long flags;
+
+	if (!(data & 0xff00)) {
+/* debug		return p->fontdata + (data & 0xff) * (fontheight(p)); */
+		if (fcache_ank[(unsigned int)(data & 0xff)].isenable) {
+			return fcache_ank[(unsigned int)(data & 0xff)].left;
+		}
+
+		/* wait for vsync */
+//		spin_lock_irqsave(&fbcon_egc_lock, flags);
+		if (vsync_irq && !in_interrupt()) {
+			outb(0x00, 0x64);
+			interruptible_sleep_on(&fbcon_egc_irq_wait);
+//			spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+		} else {
+//			spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+			while (inb(0xa0) & 0x20);
+			while (!(inb(0xa0) & 0x20));
+		}
+
+//		spin_lock_irqsave(&fbcon_egc_lock, flags);
+		outb_p(KANJI_ACCESS, EGCIO_KANJI_SETMODE);
+		outb_p(0, EGCIO_KANJI_CG_LOW);
+		outb_p(data & 0xff, EGCIO_KANJI_CG_HI);
+		memcpy(rdata, phys_to_virt(EGCRAM_KANJI_CG), 32);
+//		spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+		for (i = 0; i < 16; i++) {
+			fcache_ank[(unsigned int)(data & 0xff)].left[i]
+				 = (u8)(rdata[i] >> 8);
+		}
+
+		fcache_ank[(unsigned int)(data & 0xff)].isenable = 1;
+		return fcache_ank[(unsigned int)(data & 0xff)].left;
+	}
+
+	for (i = 0; i < NUM_CACHE; i++) {
+		if (fcache_kanji[i].isenable
+		 && fcache_kanji[i].chardata == (data & 0xff7f)) {
+			fcache_kanji_lastuse = i;
+			return ((data & 0x80) ? fcache_kanji[i].right
+					      : fcache_kanji[i].left);
+		}
+	}
+
+	do {
+		t = fcache_num;
+		fcache_num = (fcache_num + 1) & (NUM_CACHE - 1);
+	} while (t == fcache_kanji_lastuse);
+
+	fcache_kanji[t].isenable = 0;
+	fcache_kanji[t].chardata = ( data & 0xff7f );
+
+	if( (kanji_high >=0x0c && kanji_high <= 0x0f) 
+	 || kanji_high == 0x56
+	 || (kanji_high >=0x59 && kanji_high <= 0x5c)) {
+//		spin_lock_irqsave(&fbcon_egc_lock, flags);
+		outb_p(KANJI_ACCESS, EGCIO_KANJI_SETMODE);
+		outb_p(( data >> 8 ) & 0x7f, EGCIO_KANJI_CG_LOW);
+		outb_p(kanji_high , EGCIO_KANJI_CG_HI);
+		/* read left */
+		outb_p(0x20, EGCIO_KANJI_CG_LR);
+		memcpy(rdata, phys_to_virt(EGCRAM_KANJI_CG), 32);
+		/* read right */
+		outb_p(KANJI_ACCESS, EGCIO_KANJI_SETMODE);
+		outb_p(( data >> 8 ) & 0x7f, EGCIO_KANJI_CG_LOW);
+		outb_p(0x00, EGCIO_KANJI_CG_LR);
+		memcpy(&rdata[16], phys_to_virt(EGCRAM_KANJI_CG), 32);
+		outb_p(KANJI_NORMAL, EGCIO_KANJI_SETMODE);
+//		spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+		for (i = 0; i < 16; i++) {
+			fcache_kanji[t].left[i] = (u8)(rdata[i] >> 8);
+			fcache_kanji[t].right[i] = (u8)(rdata[i+16] >> 8);
+		}
+
+	} else {
+		/* read L/R pattern */
+//		spin_lock_irqsave(&fbcon_egc_lock, flags);
+		outb_p(KANJI_ACCESS, EGCIO_KANJI_SETMODE);
+		outb_p((data >> 8) & 0x7f, EGCIO_KANJI_CG_LOW);
+		outb_p(kanji_high , EGCIO_KANJI_CG_HI);
+		memcpy(rdata, phys_to_virt(EGCRAM_KANJI_CG), 32);
+		outb_p(KANJI_NORMAL, EGCIO_KANJI_SETMODE);
+//		spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+		for (i = 0; i < 16; i++) {
+			fcache_kanji[t].left[i] = (u8)(rdata[i] & 0x00ff);
+			fcache_kanji[t].right[i] = (u8)(rdata[i] >> 8);
+		}
+
+	}
+
+	fcache_kanji[t].isenable = 1;
+	return ((data & 0x80) ? fcache_kanji[t].right : fcache_kanji[t].left);
+}
+
+/* ------------------------------ */
+//#define PC98_USE_VSYNC
+#ifdef PC98_USE_VSYNC
+static void fbcon_egc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if (waitqueue_active(&fbcon_egc_irq_wait)) {
+		wake_up(&fbcon_egc_irq_wait);
+	}
+}
+#endif
+
+void fbcon_egc_setup(struct display *p)
+{
+#ifdef PC98_USE_VSYNC
+	if (vsync_irq)
+		return;
+	if (request_irq(2, fbcon_egc_interrupt, SA_INTERRUPT,
+		"CRT vsync", NULL))
+	{
+		printk("fbcon-egc: Unable to grab CRT-VSYNC interrupt IRQ2\n");
+	}
+	else {
+		vsync_irq = 2;
+		printk("fbcon-egc: grab CRT-VSYNC interrupt IRQ2\n");
+	}
+#endif
+}
+
+void fbcon_egc_bmove(struct display *p, int sy, int sx, int dy, int dx,
+		   int height, int width)
+{
+	u16 *src;
+	u16 *dest;
+	
+	int x;
+	int word_cnt;
+	unsigned long flags;
+
+	sy *= fontheight(p);
+	dy *= fontheight(p);
+	sx *= 8;
+	dx *= 8;
+	width *= 8;
+	height *= fontheight(p);
+
+	spin_lock_irqsave(&fbcon_egc_lock, flags);
+	outb(0xcf,0x7c);
+	isa_writeb(isa_readb(0x495)|0x80,0x0495);
+	outb(0x07,0x6a);	/* unprotected */
+	outb(0x05,0x6a);	/* EGC mode */
+	outb(0x06,0x6a);	/* protected */
+	outw(0xfff0,EGCIO_EGC_R0);
+	outw(0x00ff,EGCIO_EGC_R1);
+	outw(0xffff,EGCIO_EGC_R4);
+	outw(0x0000,EGCIO_EGC_R6);
+	outw(0x000f,EGCIO_EGC_R7);
+
+	outw(0x29F0,EGCIO_EGC_R2);
+//	spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+
+	if (dy < sy || (dy == sy && dx < sx)) {
+		/* forward */
+		int y;
+		u16 *save1;
+		u16 *save2;
+		src = (u16 *)(((unsigned long)p->fb_info->screen_base+(sx>>3)+
+			       sy * p->fb_info->fix.line_length) & (~1)) ;
+		dest = (u16 *)(((unsigned long)p->fb_info->screen_base+(dx>>3)+
+				dy * p->fb_info->fix.line_length) & (~1));
+		
+//		spin_lock_irqsave(&fbcon_egc_lock, flags);
+		outw((sx&0xf)|((dx&0xf)<<4),EGCIO_EGC_R6);
+//		spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+		word_cnt=((dx&0xf)+width+15)>>4;
+		if((sx&0xf) != (dx&0xf) && ((sx&0xf) > (dx&0xf) || 
+		(((sx&0xf)+width+15)>>4) > (((dx&0xf)+width+15)>>4))) {
+			word_cnt++;
+			dest=(u16 *)((unsigned long)dest-2);
+		}
+//		spin_lock_irqsave(&fbcon_egc_lock, flags);
+		outw(width-1,EGCIO_EGC_R7);
+//		spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+		for(y=0;y<height;y++) {
+			save1=src;
+			save2=dest;
+			for(x=0;x<word_cnt;x++) {
+				*dest=*src;
+				src=(u16 *)((unsigned long)src+2);
+				dest=(u16 *)((unsigned long)dest+2);
+			}
+			src=(u16 *)((unsigned long)save1+80);
+			dest=(u16 *)((unsigned long)save2+80);
+		}
+	} else {
+		/* backward */
+		int y;
+		int sb,db;
+		u16 *save1;
+		u16 *save2;
+		src  = (u16 *)(((unsigned long)p->fb_info->screen_base +
+				((sy+height-1) * p->fb_info->fix.line_length +
+				 ((sx+width-1)>>3))) & (~1));
+		dest = (u16 *)(((unsigned long)p->fb_info->screen_base +
+				((dy+height-1) * p->fb_info->fix.line_length +
+				 ((dx+width-1)>>3))) & (~1));
+//		spin_lock_irqsave(&fbcon_egc_lock, flags);
+		outw(width-1,EGCIO_EGC_R7);
+//		spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+
+		sb=((((sx+width)&0xf)-16)*(-1))&0xf;
+		db=((((dx+width)&0xf)-16)*(-1))&0xf;
+
+//		spin_lock_irqsave(&fbcon_egc_lock, flags);
+		outw(0x1000|(db<<4)|sb,EGCIO_EGC_R6);
+//		spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+		word_cnt=(db+width+15)>>4;
+
+		if (sb>db || (sb<db &&
+		   (sb+width+15)>>4 > (db+width+15)>>4)) {
+			word_cnt++;
+			dest=(u16 *)((unsigned long)dest+2);
+		}
+
+		for(y=0;y<height;y++) {
+			save1=src;
+			save2=dest;
+			for(x=0;x<word_cnt;x++) {
+				*dest=*src;
+				src=(u16 *)((unsigned long)src-2);
+				dest=(u16 *)((unsigned long)dest-2);
+			}
+			src=(u16 *)((unsigned long)save1-80);
+			dest=(u16 *)((unsigned long)save2-80);
+		}
+	}
+
+//	spin_lock_irqsave(&fbcon_egc_lock, flags);
+	outb(0x07,0x6a);	/* unprotected */
+	outb(0x04,0x6a);	/* GRCG mode */
+	outb(0x06,0x6a);	/* protected */
+	outb(0x00,0x7c);
+	isa_writeb(isa_readb(0x495)&0x7F,0x0495);
+	spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+}
+
+void fbcon_egc_clear(struct vc_data *conp, struct display *p,
+			    int sy, int sx, int height, int width)
+{
+	u16 *data;
+	int x;
+//	unsigned long flags;
+
+	sy *= fontheight(p);
+	height *= fontheight(p);
+	data = (u16 *)((unsigned long)p->fb_info->screen_base + 0x8000 + sx +
+		       sy * p->fb_info->fix.line_length);
+	data = (u16 *)((unsigned long)data & (~1));
+
+//	spin_lock_irqsave(&fbcon_egc_lock, flags);
+	outb(0xcf,0x7c);
+	isa_writeb(isa_readb(0x495)|0x80,0x0495);
+	outb(0x07,0x6a);	/* unprotected */
+	outb(0x05,0x6a);	/* EGC mode */
+	outb(0x06,0x6a);	/* protected */
+	outw(0xfff0,EGCIO_EGC_R0);
+	outw(0x00ff,EGCIO_EGC_R1);
+	outw(0xffff,EGCIO_EGC_R4);
+	outw(0x0000,EGCIO_EGC_R6);
+	outw(0x000f,EGCIO_EGC_R7);
+
+	/* egc_set_fgcolor */
+	outw(0x40ff, EGCIO_EGC_R1);
+	outw(conp ? (conp->vc_video_erase_attr>>4) & 0x0f : 0, EGCIO_EGC_R3);
+
+	outw(0x2cac,EGCIO_EGC_R2);
+//	spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+	while (height--) {
+		u16 *save=data;
+		/* first 8pixels */
+		if(sx&1) {
+			*data=0xff00;
+			data++;
+		}
+		for (x = 0; x < (width&(~1)) -1; x+=2) {
+			*data=0xffff;
+			data++;
+		}
+		/* last 8pixels */
+		if((sx+width)&1) {
+			*data=0x00ff;
+			data++;
+		}
+		/* to next line */
+		data = (u16 *)((unsigned long)save + p->fb_info->fix.line_length);
+	}
+
+//	spin_lock_irqsave(&fbcon_egc_lock, flags);
+	outb(0x07,0x6a);	/* unprotected */
+	outb(0x04,0x6a);	/* GRCG mode */
+	outb(0x06,0x6a);	/* protected */
+	outb(0x00,0x7c);
+	isa_writeb(isa_readb(0x495)&0x7F,0x0495);
+//	spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+}
+
+
+void fbcon_egc_putc(struct vc_data *conp, struct display *p, int ch, int yy, int xx)
+{
+	u16 *data;
+	u8 *fdata_s;
+	int fg;
+	int bg;
+	int isbold;
+	int isuline;
+	int y;
+	unsigned long flags;
+
+	data = (u16 *)((unsigned long)p->fb_info->screen_base + xx +
+			    yy * p->fb_info->fix.line_length * fontheight(p));
+	
+	fg = conp->vc_pc98_addbuf & 0x0f;
+	bg = (conp->vc_pc98_addbuf >> 4) & 0x0f;
+	isbold = conp->vc_pc98_addbuf & 0x100;
+	isuline = conp->vc_pc98_addbuf & 0x200;
+	data = (u16 *)((unsigned long)data & (~1));
+
+	spin_lock_irqsave(&fbcon_egc_lock, flags);
+	fdata_s = egc_load_facedata(p, ch);
+	outb(0xcf,0x7c);
+	isa_writeb(isa_readb(0x495)|0x80,0x0495);
+	outb(0x07,0x6a);	/* unprotected */
+	outb(0x05,0x6a);	/* EGC mode */
+	outb(0x06,0x6a);	/* protected */
+	outw(0xfff0,EGCIO_EGC_R0);
+	outw(0x00ff,EGCIO_EGC_R1);
+	outw(0xffff,EGCIO_EGC_R4);
+	outw(0x0000,EGCIO_EGC_R6);
+	outw(0x000f,EGCIO_EGC_R7);
+
+	outw(0x2cac,EGCIO_EGC_R2);
+//	spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+	/* write one character */
+	for (y = 0; y < fontheight(p); y++) {
+		u16 mask=(*(fdata_s+y))<<((xx&1)<<3);
+		if (isbold)
+			mask |= (mask << 1);
+		if ( y == fontheight(p) - 1 && isuline)
+			mask = (0xff) << ((xx&1)<<3) ;
+		/* egc_set_fgcolor */
+//		spin_lock_irqsave(&fbcon_egc_lock, flags);
+		outw(0x40ff, EGCIO_EGC_R1);
+		outw(fg, EGCIO_EGC_R3);
+//		spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+
+		*data = mask;
+		if(isbold && !(xx&2) && xx!=0 && *(fdata_s+y)&0x80) {
+			*(data-1) = 0x0100;
+		}
+		/* egc_set_fgcolor */
+//		spin_lock_irqsave(&fbcon_egc_lock, flags);
+		outw(0x40ff, EGCIO_EGC_R1);
+		outw(bg, EGCIO_EGC_R3);
+//		spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+
+		mask ^= 0xff<<((xx&1)<<3);
+		*data = mask;
+		data = (u16 *)((unsigned long)data + p->fb_info->fix.line_length);
+	}
+
+//	spin_lock_irqsave(&fbcon_egc_lock, flags);
+	outb(0x07,0x6a);	/* unprotected */
+	outb(0x04,0x6a);	/* GRCG mode */
+	outb(0x06,0x6a);	/* protected */
+	outb(0x00,0x7c);
+	isa_writeb(isa_readb(0x495)&0x7F,0x0495);
+	spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+}
+
+void fbcon_egc_putcs(struct vc_data *conp, struct display *p,
+			    const unsigned short *s,
+			    int count, int yy, int xx)
+{
+	u16 *data;
+	extern int	fbcon_softback_size;
+	int attr;
+	int fg;
+	int bg;
+	int isbold;
+	int isuline;
+	int n,y;
+	unsigned long flags;
+
+	data = (u16 *)((unsigned long)p->fb_info->screen_base +
+			    xx + yy * p->fb_info->fix.line_length * fontheight(p));
+	
+	attr = scr_readw((u16 *)((unsigned long)s +
+			((s >= conp->vc_screenbuf
+				&& (unsigned long)s <
+				(unsigned long)(conp->vc_screenbuf)
+				+ conp->vc_screenbuf_size) ?
+			conp->vc_screenbuf_size : fbcon_softback_size)));
+	fg = attr & 0x0f;
+	bg = ( attr >> 4) & 0x0f;
+	isbold = attr & 0x100;
+	isuline = attr & 0x200;
+	data = (u16 *)((unsigned long)data & ~1);
+
+	spin_lock_irqsave(&fbcon_egc_lock, flags);
+	outb(0xcf,0x7c);
+	isa_writeb(isa_readb(0x495)|0x80,0x0495);
+	outb(0x07,0x6a);	/* unprotected */
+	outb(0x05,0x6a);	/* EGC mode */
+	outb(0x06,0x6a);	/* protected */
+	outw(0xfff0,EGCIO_EGC_R0);
+	outw(0x00ff,EGCIO_EGC_R1);
+	outw(0xffff,EGCIO_EGC_R4);
+	outw(0x0000,EGCIO_EGC_R6);
+	outw(0x000f,EGCIO_EGC_R7);
+
+	outw(0x2cac,EGCIO_EGC_R2);
+//	spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+	if(xx & 1) {
+		/* write one character */
+		int c = scr_readw(s++);
+		u8 *fdata_s = egc_load_facedata(p, c);
+		for (y = 0; y < fontheight(p); y++) {
+			u16 mask=(*(fdata_s+y))<<8;
+			if (isbold)
+				mask |= (mask << 1);
+			if ( y == fontheight(p) - 1 && isuline)
+				mask = 0xff00 ;
+			/* egc_set_fgcolor */
+//			spin_lock_irqsave(&fbcon_egc_lock, flags);
+			outw(0x40ff, EGCIO_EGC_R1);
+			outw(fg, EGCIO_EGC_R3);
+//			spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+
+			*data = mask;
+			/* egc_set_fgcolor */
+//			spin_lock_irqsave(&fbcon_egc_lock, flags);
+			outw(0x40ff, EGCIO_EGC_R1);
+			outw(bg, EGCIO_EGC_R3);
+//			spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+
+			mask ^= 0xff00;
+			*data = mask;
+			data = (u16 *)((unsigned long)data + p->fb_info->fix.line_length);
+		}
+		data = (u16 *)((unsigned long)data + 2 -
+			       p->fb_info->fix.line_length * fontheight(p));
+		xx++;
+		count--;
+	}
+
+	for (n = 0; n < (count&(~1)) - 1 ; n += 2 ) {
+		int c,i;
+		u8 *fdata_s[2];
+		for(i=0;i<2;i++) {
+			c = scr_readw(s++);
+			fdata_s[i] = egc_load_facedata(p, c);
+		}
+		for (y = 0; y < fontheight(p); y++) {
+			u16 mask=((*(fdata_s[1]+y))<<8)|(*(fdata_s[0]+y));
+			if (isbold)
+				mask |= (((mask << 1) & 0xfeff)|(mask >> 15));
+			if ( y == fontheight(p) - 1 && isuline)
+				mask = 0xffff ;
+			/* egc_set_fgcolor */
+//			spin_lock_irqsave(&fbcon_egc_lock, flags);
+			outw(0x40ff, EGCIO_EGC_R1);
+			outw(fg, EGCIO_EGC_R3);
+//			spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+
+			*data = mask;
+			if (isbold && !(xx&2) && xx!=0
+			&&  *(fdata_s[0]+y)&0x80) {
+				*(data-1) = 0x0100;
+			}
+			/* egc_set_fgcolor */
+//			spin_lock_irqsave(&fbcon_egc_lock, flags);
+			outw(0x40ff, EGCIO_EGC_R1);
+			outw(bg, EGCIO_EGC_R3);
+//			spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+
+			mask ^= 0xffff;
+			*data = mask;
+			data = (u16 *)((unsigned long)data + p->fb_info->fix.line_length);
+		}
+		data = (u16 *)((unsigned long)data + 2 -
+			       p->fb_info->fix.line_length * fontheight(p));
+	}
+
+	if (count &1) {
+		/* write one character */
+		int c = scr_readw(s++);
+		u8 *fdata_s = egc_load_facedata(p, c);
+		for (y = 0; y < fontheight(p); y++) {
+			u16 mask=(*(fdata_s+y));
+			if (isbold)
+				mask |= (mask << 1);
+			if ( y == fontheight(p) - 1 && isuline)
+				mask = 0x00ff ;
+			mask &= 0x00ff;
+			/* egc_set_fgcolor */
+//			spin_lock_irqsave(&fbcon_egc_lock, flags);
+			outw(0x40ff, EGCIO_EGC_R1);
+			outw(fg, EGCIO_EGC_R3);
+//			spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+
+			if(isbold && !(xx&2) && xx!=0 && *(fdata_s+y)&0x80) {
+				*(data-1) = 0x0100;
+			}
+			*data = mask;
+			/* egc_set_fgcolor */
+//			spin_lock_irqsave(&fbcon_egc_lock, flags);
+			outw(0x40ff, EGCIO_EGC_R1);
+			outw(bg, EGCIO_EGC_R3);
+//			spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+
+			mask ^= 0xff;
+			*data = mask;
+			data = (u16 *)((unsigned long)data + p->fb_info->fix.line_length);
+		}
+	}
+
+//	spin_lock_irqsave(&fbcon_egc_lock, flags);
+	outb(0x07,0x6a);	/* unprotected */
+	outb(0x04,0x6a);	/* GRCG mode */
+	outb(0x06,0x6a);	/* protected */
+	outb(0x00,0x7c);
+	isa_writeb(isa_readb(0x495)&0x7F,0x0495);
+	spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+}
+
+void fbcon_egc_revc(struct display *p, int xx, int yy)
+{
+	u16 *data;
+	int y;
+//	unsigned long flags;
+
+	data = (u16 *)((unsigned long)p->fb_info->screen_base + xx + 0x8000 +
+			    yy * p->fb_info->fix.line_length * fontheight(p));
+	data = (u16 *)((unsigned long)data & (~1));
+
+//	spin_lock_irqsave(&fbcon_egc_lock, flags);
+	outb(0xcf,0x7c);
+	isa_writeb(isa_readb(0x495)|0x80,0x0495);
+	outb(0x07,0x6a);	/* unprotected */
+	outb(0x05,0x6a);	/* EGC mode */
+	outb(0x06,0x6a);	/* protected */
+	outw(0xfff0,EGCIO_EGC_R0);
+	outw(0x00ff,EGCIO_EGC_R1);
+	outw(0xffff,EGCIO_EGC_R4);
+	outw(0x0000,EGCIO_EGC_R6);
+	outw(0x000f,EGCIO_EGC_R7);
+
+	outw(0x2833, EGCIO_EGC_R2);
+	outw(0xff << ((xx & 1) << 3), EGCIO_EGC_R4);
+//	spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+	
+	for (y = 0; y < fontheight(p); y++) {
+		*data = 0xAAAA;
+		data = (u16 *)((unsigned long)data +p->fb_info->fix.line_length);
+	}
+
+//	spin_lock_irqsave(&fbcon_egc_lock, flags);
+	outb(0x07,0x6a);	/* unprotected */
+	outb(0x04,0x6a);	/* GRCG mode */
+	outb(0x06,0x6a);	/* protected */
+	outb(0x00,0x7c);
+	isa_writeb(isa_readb(0x495)&0x7F,0x0495);
+//	spin_unlock_irqrestore(&fbcon_egc_lock, flags);
+}
+
+struct display_switch fbcon_egc = {
+    fbcon_egc_setup, fbcon_egc_bmove, fbcon_egc_clear,
+    fbcon_egc_putc, fbcon_egc_putcs, fbcon_egc_revc,
+    NULL, NULL, NULL, FONTWIDTH(8)
+};
+
+#ifdef MODULE
+int init_module(void)
+{
+    return 0;
+}
+
+void cleanup_module(void)
+{
+	/* Nothing to do. */
+}
+#endif /* MODULE */
+
+
+    /*
+     *	Visible symbols for modules
+     */
+
+EXPORT_SYMBOL(fbcon_egc);
+EXPORT_SYMBOL(fbcon_egc_setup);
+EXPORT_SYMBOL(fbcon_egc_bmove);
+EXPORT_SYMBOL(fbcon_egc_clear);
+EXPORT_SYMBOL(fbcon_egc_putc);
+EXPORT_SYMBOL(fbcon_egc_putcs);
+EXPORT_SYMBOL(fbcon_egc_revc);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff -urN linux/drivers/video/fbcon.c linux98/drivers/video/fbcon.c
--- linux/drivers/video/fbcon.c	Sun Sep  1 07:04:50 2002
+++ linux98/drivers/video/fbcon.c	Mon Sep  2 15:23:26 2002
@@ -572,7 +572,11 @@
     if (con == fg_console && info->fix.type != FB_TYPE_TEXT) {   
 	if (fbcon_softback_size) {
 	    if (!softback_buf) {
+#ifndef CONFIG_PC9800
 		softback_buf = (unsigned long)kmalloc(fbcon_softback_size, GFP_KERNEL);
+#else
+		softback_buf = (unsigned long)kmalloc(fbcon_softback_size * 2, GFP_KERNEL);
+#endif
 		if (!softback_buf) {
     	            fbcon_softback_size = 0;
     	            softback_top = 0;
@@ -658,16 +662,35 @@
     	q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows);
     	step = logo_lines * old_cols;
     	for (r = q - logo_lines * old_cols; r < q; r++)
+#ifndef CONFIG_PC9800
     	    if (scr_readw(r) != conp->vc_video_erase_char)
+#else
+	    if (scr_readw((unsigned short *)((unsigned long)r+conp->vc_screenbuf_size)) !=
+		conp->vc_video_erase_attr &&
+		scr_readw(r) != conp->vc_video_erase_char)
+#endif
     	    	break;
 	if (r != q && nr_rows >= old_rows + logo_lines) {
+#ifndef CONFIG_PC9800
     	    save = kmalloc(logo_lines * nr_cols * 2, GFP_KERNEL);
+#else
+	    save = kmalloc(logo_lines * nr_cols * 2 * 2, GFP_KERNEL);
+#endif
     	    if (save) {
     	        int i = old_cols < nr_cols ? old_cols : nr_cols;
     	    	scr_memsetw(save, conp->vc_video_erase_char, logo_lines * nr_cols * 2);
+#ifdef CONFIG_PC9800
+		scr_memsetw((u16 *)((unsigned long)save + logo_lines * nr_cols * 2),
+			     conp->vc_video_erase_attr, logo_lines * nr_cols * 2);
+#endif
     	    	r = q - step;
-    	    	for (cnt = 0; cnt < logo_lines; cnt++, r += i)
+    	    	for (cnt = 0; cnt < logo_lines; cnt++, r += i) {
     	    		scr_memcpyw(save + cnt * nr_cols, r, 2 * i);
+#ifdef CONFIG_PC9800
+			scr_memcpyw((unsigned short *)((unsigned long)(save + logo_lines * nr_cols * 2)) + cnt * nr_cols,
+					 (unsigned short *)((unsigned long)r + conp->vc_screenbuf_size), 2 * i);
+#endif
+		}
     	    	r = q;
     	    }
     	}
@@ -676,6 +699,14 @@
 	    r = q - step - old_cols;
     	    for (cnt = old_rows - logo_lines; cnt > 0; cnt--) {
     	    	scr_memcpyw(r + step, r, conp->vc_size_row);
+#ifdef CONFIG_PC9800
+		scr_memcpyw((unsigned short *)((unsigned long)r
+					       + conp->vc_screenbuf_size)
+			    + step,
+			    (unsigned short *)((unsigned long)r
+					       + conp->vc_screenbuf_size),
+			    conp->vc_size_row);
+#endif
     	    	r -= old_cols;
     	    }
     	    if (!save) {
@@ -686,6 +717,12 @@
     	scr_memsetw((unsigned short *)conp->vc_origin,
 		    conp->vc_video_erase_char, 
 		    conp->vc_size_row * logo_lines);
+#ifdef CONFIG_PC9800
+	scr_memsetw((unsigned short *)((unsigned long)conp->vc_origin
+				       + conp->vc_screenbuf_size),
+		    conp->vc_video_erase_attr, 
+		    conp->vc_size_row * logo_lines);
+#endif
     }
     
     /*
@@ -734,10 +771,25 @@
 	    if (p->dispsw->clear_margins)
 		p->dispsw->clear_margins(conp, p, 0);
 	    update_screen(con);
+#ifdef CONFIG_PC9800
+	    /* reset attributes because of incompatibility */
+	    scr_memsetw((unsigned short *)((unsigned long)conp->vc_origin
+					   + conp->vc_screenbuf_size),
+			0x07, conp->vc_size_row * logo_lines);
+	    /* and redraw once more */
+	    update_screen(con);
+#endif
 	}
 	if (save) {
     	    q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows);
 	    scr_memcpyw(q, save, logo_lines * nr_cols * 2);
+#ifdef CONFIG_PC9800
+	    scr_memcpyw((unsigned short *)((unsigned long)q
+					   + conp->vc_screenbuf_size),
+			(unsigned short *)((unsigned long)save
+					   + logo_lines * nr_cols * 2),
+			logo_lines * nr_cols * 2);
+#endif
 	    conp->vc_y += logo_lines;
     	    conp->vc_pos += logo_lines * conp->vc_size_row;
     	    kfree(save);
@@ -1034,10 +1086,18 @@
     unsigned long n;
     int line = 0;
     int count = conp->vc_rows;
+#ifdef CONFIG_PC9800
+    int save_bufsiz = conp->vc_screenbuf_size;
+    int d_sb = 1;
+#endif
     
     d = (u16 *)softback_curr;
-    if (d == (u16 *)softback_in)
+    if (d == (u16 *)softback_in) {
 	d = (u16 *)conp->vc_origin;
+#ifdef CONFIG_PC9800
+	d_sb=0;
+#endif
+	}
     n = softback_curr + delta * conp->vc_size_row;
     softback_lines -= delta;
     if (delta < 0) {
@@ -1063,25 +1123,47 @@
 	    softback_lines = 0;
 	}
     }
-    if (n == softback_curr)
+    if (n == softback_curr) {
+#ifdef CONFIG_PC9800
+	conp->vc_screenbuf_size = save_bufsiz;
+#endif
     	return;
+	}
     softback_curr = n;
     s = (u16 *)softback_curr;
-    if (s == (u16 *)softback_in)
+#ifdef CONFIG_PC9800
+    conp->vc_screenbuf_size = fbcon_softback_size;
+#endif
+    if (s == (u16 *)softback_in) {
 	s = (u16 *)conp->vc_origin;
+#ifdef CONFIG_PC9800
+	conp->vc_screenbuf_size = save_bufsiz;
+#endif
+	}
     while (count--) {
 	unsigned short *start;
 	unsigned short *le;
 	unsigned short c;
 	int x = 0;
 	unsigned short attr = 1;
+#ifdef CONFIG_PC9800
+	unsigned short ca;
+#endif
 
 	start = s;
 	le = advance_row(s, 1);
 	do {
 	    c = scr_readw(s);
+#ifdef CONFIG_PC9800
+	    ca= scr_readw((unsigned short *)((unsigned long)s+conp->vc_screenbuf_size));
+#endif
+#ifndef CONFIG_PC9800
 	    if (attr != (c & 0xff00)) {
 		attr = c & 0xff00;
+#else
+	    if (attr != ca) {
+		attr = ca;
+#endif
 		if (s > start) {
 		    p->dispsw->putcs(conp, p, start, s - start,
 				     real_y(p, line), x);
@@ -1089,7 +1171,15 @@
 		    start = s;
 		}
 	    }
+#ifndef CONFIG_PC9800
 	    if (c == scr_readw(d)) {
+#else
+	    if (c == scr_readw(d)
+		&& ca == scr_readw((unsigned short *)
+				   ((unsigned long)d
+				    + (d_sb ? fbcon_softback_size
+				       : conp->vc_screenbuf_size)))) {
+#endif
 	    	if (s > start) {
 	    	    p->dispsw->putcs(conp, p, start, s - start,
 				     real_y(p, line), x);
@@ -1106,15 +1196,34 @@
 	if (s > start)
 	    p->dispsw->putcs(conp, p, start, s - start, real_y(p, line), x);
 	line++;
-	if (d == (u16 *)softback_end)
+	if (d == (u16 *)softback_end) {
 	    d = (u16 *)softback_buf;
-	if (d == (u16 *)softback_in)
+#ifdef CONFIG_PC9800
+	    d_sb = 1;
+#endif
+	}
+	if (d == (u16 *)softback_in) {
 	    d = (u16 *)conp->vc_origin;
-	if (s == (u16 *)softback_end)
+#ifdef CONFIG_PC9800
+	    d_sb = 0;
+#endif
+	}
+	if (s == (u16 *)softback_end) {
 	    s = (u16 *)softback_buf;
-	if (s == (u16 *)softback_in)
+#ifdef CONFIG_PC9800
+	    conp->vc_screenbuf_size = fbcon_softback_size;
+#endif
+	}
+	if (s == (u16 *)softback_in) {
 	    s = (u16 *)conp->vc_origin;
+#ifdef CONFIG_PC9800
+	    conp->vc_screenbuf_size = save_bufsiz;
+#endif
     }
+    }
+#ifdef CONFIG_PC9800
+    conp->vc_screenbuf_size = save_bufsiz;
+#endif
 }
 
 static void fbcon_redraw(struct vc_data *conp, struct display *p, 
@@ -1130,11 +1239,23 @@
 	unsigned short c;
 	int x = 0;
 	unsigned short attr = 1;
+#ifdef CONFIG_PC9800
+	unsigned short ca;
+#endif
 
 	do {
 	    c = scr_readw(s);
+#ifdef CONFIG_PC9800
+	    ca = scr_readw((unsigned short *)((unsigned long)s
+					      + conp->vc_screenbuf_size));
+#endif
+#ifndef CONFIG_PC9800
 	    if (attr != (c & 0xff00)) {
 		attr = c & 0xff00;
+#else
+	    if (attr != ca) {
+		attr = ca;
+#endif
 		if (s > start) {
 		    p->dispsw->putcs(conp, p, start, s - start,
 				     real_y(p, line), x);
@@ -1142,7 +1263,14 @@
 		    start = s;
 		}
 	    }
+#ifndef CONFIG_PC9800
 	    if (c == scr_readw(d)) {
+#else
+	    if (c == scr_readw(d)
+		&& ca == scr_readw((unsigned short *)
+				   ((unsigned long)d
+				    + conp->vc_screenbuf_size))) {
+#endif
 	    	if (s > start) {
 	    	    p->dispsw->putcs(conp, p, start, s - start,
 				     real_y(p, line), x);
@@ -1154,6 +1282,10 @@
 	    	}
 	    }
 	    scr_writew(c, d);
+#ifdef CONFIG_PC9800
+	    scr_writew(ca, (unsigned short *)((unsigned long)d
+					      + conp->vc_screenbuf_size));
+#endif
 	    console_conditional_schedule();
 	    s++;
 	    d++;
@@ -1231,18 +1363,37 @@
 	unsigned short c;
 	int x = dx;
 	unsigned short attr = 1;
+#ifdef CONFIG_PC9800
+	unsigned short ca;
+#endif
 
 	do {
 	    c = scr_readw(d);
+#ifdef CONFIG_PC9800
+	    ca = scr_readw((unsigned short *)((unsigned long)s
+					      + conp->vc_screenbuf_size));
+#endif
+#ifndef CONFIG_PC9800
 	    if (attr != (c & 0xff00)) {
 		attr = c & 0xff00;
+#else
+	    if (attr != ca) {
+		attr = ca;
+#endif
 		if (d > start) {
 		    p->dispsw->putcs(conp, p, start, d - start, dy, x);
 		    x += d - start;
 		    start = d;
 		}
 	    }
+#ifndef CONFIG_PC9800
 	    if (s >= ls && s < le && c == scr_readw(s)) {
+#else
+	    if (s >= ls && s < le && c == scr_readw(s)
+		&& ca == scr_readw((unsigned short *)
+				   ((unsigned long)d
+				    + conp->vc_screenbuf_size))) {
+#endif
 		if (d > start) {
 		    p->dispsw->putcs(conp, p, start, d - start, dy, x);
 		    x += d - start + 1;
@@ -1272,6 +1423,11 @@
 
     while (count) {
     	scr_memcpyw((u16 *)softback_in, p, conp->vc_size_row);
+#ifdef CONFIG_PC9800
+	scr_memcpyw((u16 *)((unsigned long)softback_in+fbcon_softback_size),
+		    (u16 *)((unsigned long)p+ conp->vc_screenbuf_size),
+		    conp->vc_size_row);
+#endif
     	count--;
     	p = advance_row(p, 1);
     	softback_in += conp->vc_size_row;
@@ -1367,6 +1523,14 @@
 		    	    conp->vc_size_row * (b-count)), 
 		    	    conp->vc_video_erase_char,
 		    	    conp->vc_size_row * count);
+#ifdef CONFIG_PC9800
+		scr_memsetw((unsigned short *)((unsigned long)conp->vc_origin
+					       + conp->vc_screenbuf_size
+					       + (conp->vc_size_row
+						  * (b - count))),
+			    conp->vc_video_erase_attr,
+			    conp->vc_size_row * count);
+#endif
 		return 1;
 	    }
 	    break;
@@ -1427,6 +1591,13 @@
 	    		    conp->vc_size_row * t), 
 	    		    conp->vc_video_erase_char,
 	    		    conp->vc_size_row * count);
+#ifdef CONFIG_PC9800
+		scr_memsetw((unsigned short *)((unsigned long)conp->vc_origin
+					       + conp->vc_screenbuf_size
+					       + conp->vc_size_row * t),
+			    conp->vc_video_erase_attr,
+			    conp->vc_size_row * count);
+#endif
 	    	return 1;
 	    }
     }
@@ -2015,6 +2186,7 @@
 static void fbcon_invert_region(struct vc_data *conp, u16 *p, int cnt)
 {
     while (cnt--) {
+#ifndef CONFIG_PC9800
 	u16 a = scr_readw(p);
 	if (!conp->vc_can_do_color)
 	    a ^= 0x0800;
@@ -2023,6 +2195,19 @@
 	else
 	    a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
 	scr_writew(a, p++);
+#else
+	    u16 *attr;
+	    if (p >= conp->vc_screenbuf
+			&& (unsigned long)p <
+				(unsigned long)(conp->vc_screenbuf)
+					+ conp->vc_screenbuf_size)
+		attr = (u16 *)((unsigned long)p + conp->vc_screenbuf_size);
+	    else
+		attr = (u16 *)((unsigned long)p + fbcon_softback_size);
+
+	scr_writew(((*attr) & 0xff00) | (((*attr) & 0x00f0) >> 4) | (((*attr) & 0x000f) << 4), attr);
+	p++;
+#endif
 	if (p == (u16 *)softback_end)
 	    p = (u16 *)softback_buf;
 	if (p == (u16 *)softback_in)
@@ -2059,6 +2244,13 @@
     		    	p -= conp->vc_size_row;
     		    	q -= conp->vc_size_row;
     		    	scr_memcpyw((u16 *)q, (u16 *)p, conp->vc_size_row);
+#ifdef CONFIG_PC9800
+			scr_memcpyw((u16 *)((unsigned long)q
+					    + conp->vc_screenbuf_size),
+				    (u16 *)((unsigned long)p
+					    + fbcon_softback_size),
+				    conp->vc_size_row);
+#endif
     		    }
     		    softback_in = p;
     		    update_region(unit, conp->vc_origin, logo_lines * conp->vc_cols);
@@ -2411,6 +2603,7 @@
 	}
 #endif
 #if defined(CONFIG_FBCON_VGA_PLANES)
+#ifndef CONFIG_PC9800
 	if (depth == 4 && info->fix.type == FB_TYPE_VGA_PLANES) {
 		outb_p(1,0x3ce); outb_p(0xf,0x3cf);
 		outb_p(3,0x3ce); outb_p(0,0x3cf);
@@ -2441,6 +2634,220 @@
 		done = 1;
 	}
 #endif			
+#endif
+#if defined(CONFIG_PC9800)
+	if (depth == 4 && info->fix.type == FB_TYPE_VGA_PLANES) {
+		/*
+		 * for GRCG framebuffers (EGC not required)
+		 */
+		u8 pldata[4], cpudata, data;
+		int hi_lo = 0, ti;
+#if 1
+#if 0
+		/* mono-bmp */
+		static u16 egcfblogo[144] = {
+		0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+		0x0000, 0x0000, 0x0000, 0x0000,
+		0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+		0x0000, 0x0000, 0x0000, 0x0000,
+		0xF003, 0x0000, 0x0000, 0x0000, 0x0000,
+		0x0000, 0x0000, 0x0000, 0x0000,
+		0x0C0C, 0x0000, 0x0000, 0x0000, 0x0000,
+		0x0000, 0x0000, 0x0000, 0x0000,
+		0x2211, 0xF101, 0xC1C1, 0xC3F7, 0x0080,
+		0x0000, 0x0041, 0x0500, 0x00C7,
+		0x2121, 0x0201, 0x2122, 0x2404, 0x0040,
+		0x0000, 0x0040, 0x0600, 0x8028,
+		0x2041, 0x0481, 0x0114, 0x2804, 0x780E,
+		0xF01C, 0x7941, 0x4A14, 0x8028,
+		0x2041, 0xF481, 0x0104, 0xE8E7, 0x4411,
+		0x8822, 0x4541, 0x8A12, 0x0027,
+		0x0040, 0x0481, 0x0174, 0x2804, 0x4411,
+		0x8822, 0x4541, 0x0911, 0x80E8,
+		0x0040, 0x0481, 0x0114, 0x2804, 0x4411,
+		0x8822, 0x4541, 0x0811, 0x8028,
+		0x0120, 0x0201, 0x2122, 0x2404, 0x4451,
+		0x8822, 0x4541, 0x9232, 0x8028,
+		0x0210, 0xF101, 0xC1C1, 0xC307, 0x448E,
+		0x881C, 0x447D, 0x51D4, 0x00C7,
+		0x0C0C, 0x0000, 0x0000, 0x0000, 0x0000,
+		0x0000, 0x0000, 0x0000, 0x0000,
+		0xF003, 0x0000, 0x0000, 0x0000, 0x0000,
+		0x0000, 0x0000, 0x0000, 0x0000,
+		0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+		0x0000, 0x0000, 0x0000, 0x0000,
+		0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+		0x0000, 0x0000, 0x0000, 0x0000,};
+#endif
+		static unsigned short kmc_logo_data[] /* __initlocaldata */ = {
+			0x0000, 0x0000, 0x8007, 0x0000, 0x0000, 0x0000,
+			0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+			0x0000, 0x0000, 0x800F, 0x0000, 0x0000, 0x0000,
+			0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+			0x0000, 0x0000, 0x800F, 0x0000, 0x0000, 0x0000,
+			0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+			0x0000, 0x3800, 0x801F, 0x0000, 0x0000, 0xC000,
+			0x0000, 0x0000, 0x0200, 0x0000, 0x0000,
+			0x0000, 0x7800, 0x803F, 0x0000, 0xF00F, 0xC000,
+			0x0000, 0x0000, 0x0400, 0x000F, 0x003E,
+			0x0000, 0xF800, 0x803F, 0x0000, 0x8001, 0x0000,
+			0x0000, 0x0000, 0x0400, 0xC031, 0x00C3,
+			0x0000, 0xF800, 0x807F, 0x0000, 0x8001, 0x0000,
+			0x0000, 0x0000, 0x0400, 0x4160, 0x8081,
+			0x0000, 0xF801, 0x80FF, 0x0000, 0x8001, 0x0000,
+			0x0000, 0x0000, 0x0800, 0x6140, 0x8081,
+			0x0000, 0xF903, 0x80FF, 0x0000, 0x8001, 0x0000,
+			0x0000, 0x0000, 0x0800, 0x31C0, 0x8081,
+			0x0000, 0xF903, 0x80FF, 0x0000, 0x8001, 0x0000,
+			0x0000, 0x0000, 0x0800, 0x31C0, 0x00C1,
+			0x0000, 0xFB07, 0x80F7, 0x0000, 0x8001, 0xC100,
+			0x1E8E, 0x7C1E, 0x107C, 0x30C0, 0x00E3,
+			0x0000, 0xFF0F, 0xC0F7, 0x0000, 0x8001, 0xC703,
+			0x06BF, 0x1806, 0x1030, 0x30C0, 0x0074,
+			0x1EFE, 0xBF0F, 0xF0E7, 0xFE03, 0x8001, 0xC100,
+			0x86E3, 0x0C06, 0x1020, 0x30E0, 0x0038,
+			0x1CFE, 0x3F1F, 0xE0C7, 0xFE01, 0x8001, 0xC100,
+			0x8681, 0x0E06, 0x2040, 0x3060, 0x003C,
+			0x1CFE, 0x3F3E, 0xE087, 0xFE00, 0x8001, 0xC100,
+			0x8681, 0x0606, 0x2080, 0x7030, 0x004E,
+			0x18FE, 0x3F3E, 0xC187, 0xFEE3, 0x8001, 0xC100,
+			0x8681, 0x0306, 0x2080, 0xA01F, 0x00C7,
+			0x10FE, 0x3F7C, 0xC307, 0xFEFF, 0x8001, 0xC100,
+			0x8681, 0x0106, 0x4080, 0x6100, 0x8083,
+			0x10FE, 0x00F8, 0xC307, 0xFEFF, 0x8001, 0xC100,
+			0x8681, 0x0206, 0x40C0, 0xC100, 0x8081,
+			0x00FE, 0x00F8, 0x8307, 0xFEFF, 0x8001, 0xC110,
+			0x8681, 0x0406, 0x4060, 0x8100, 0x8081,
+			0x00FE, 0x00F0, 0x8307, 0xFEFF, 0x8001, 0xC120,
+			0x8681, 0x0806, 0x8070, 0x8101, 0x8081,
+			0x10FE, 0x0060, 0xC307, 0xFEFF, 0x8001, 0xC120,
+			0x8781, 0x101E, 0x8038, 0x0006, 0x00C1,
+			0x18FE, 0x0040, 0xC107, 0xFEF3, 0x8001, 0xC1E0,
+			0x8381, 0xB0F7, 0x801C, 0x001C, 0x00C3,
+			0x18FE, 0x0000, 0xC007, 0xFE01, 0xFF0F, 0xF7C3,
+			0xE1E7, 0x78C6, 0x007F, 0x00F0, 0x003C,
+			0x1CFE, 0x0000, 0xE007, 0xFE01, 0x0000, 0x0000,
+			0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+			0x1EFE, 0x0000, 0xF007, 0xFE01, 0x0000, 0x0000,
+			0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+			0x1EFE, 0x0000, 0xFC07, 0xFE07, 0x0000, 0x0000,
+			0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+			0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+			0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+			0x1CE0, 0x8001, 0x0F08, 0xE000, 0x0038, 0x1C00,
+			0x8007, 0x0CE0, 0x8003, 0x0848, 0x8008,
+			0x1290, 0x4002, 0x0808, 0x0001, 0x0010, 0x2000,
+			0x0004, 0x1290, 0x4002, 0x0848, 0x800D,
+			0x1CE0, 0x4002, 0x0E08, 0x0001, 0x0010, 0x1800,
+			0x0007, 0x1EE0, 0x8003, 0x0878, 0x800A,
+			0x1280, 0x4002, 0x0848, 0x0001, 0x0010, 0x0400,
+			0x0004, 0x1290, 0x0002, 0x0848, 0x8008,
+			0x1280, 0x8001, 0x0F30, 0xE000, 0x0010, 0x3800,
+			0x8007, 0x1290, 0x0002, 0x0848, 0x8008
+		};
+
+#endif
+		/* setup ; GRCG ON */
+		outb(0xc0, 0x7c);
+#if 1
+		/* Logo test :-) */
+		if (x == 0) {
+			int lg_start_x;
+			int lg_wd_x;
+			/* clearing by pal no.0 */
+			outb(0x00, 0x7e);
+			outb(0x00, 0x7e);
+			outb(0x00, 0x7e);
+			outb(0x00, 0x7e);
+			for (y1 = 0; y1 < LOGO_H; y1++) {
+				for (x1 = 0; x1 < 40; x1 ++) {
+				dst = fb + y1 * line + x1 * 2;
+				*((u16 *)dst) = 0xffff;
+				}
+			}
+			/* draw Linux/98 */
+			lg_start_x = num_online_cpus() * (LOGO_W + 8) - 8;
+			lg_wd_x = (lg_start_x + 15) >> 4;
+			if (lg_wd_x + 11 <= 40 && LOGO_H >= 32) {
+				int ptr = ((40 - lg_wd_x) + lg_wd_x * 2 - 11) / 2;
+				outb(0xff, 0x7e);
+				outb(0xff, 0x7e);
+				outb(0xff, 0x7e);
+				outb(0xff, 0x7e);
+				for (y1 = 0; y1 < 32; y1++) {
+					for (x1 = 0; x1 < 11; x1 ++) {
+					dst = fb + (y1 + (LOGO_H >> 1) - 16) * 
+					      line + ((x1 + ptr) * 2);
+					*((u16 *)dst) = kmc_logo_data[y1 * 11 + x1];
+					}
+				}
+			}
+#if 0
+			/* draw egc logo */
+			if (LOGO_H >= 16 && lg_wd_x + 9 <= 40) {
+				outb(0xff, 0x7e);
+				outb(0xff, 0x7e);
+				outb(0x00, 0x7e);
+				outb(0x00, 0x7e);
+				for (y1 = 0; y1 < 16; y1++) {
+					for (x1 = 0; x1 < 9; x1 ++) {
+					dst = fb + (y1) * 
+					      line + (line - 18 + x1 * 2) ;
+					*((u16 *)dst) = egcfblogo[y1 * 9 + x1];
+					}
+				}
+			}
+#endif
+		}
+#endif
+		/* Drawing Penguins... */
+		src = logo;
+		for (y1 = 0; y1 < LOGO_H; y1++) {
+			/* data stack */
+			cpudata = 0;
+			for (ti = 0; ti < 4; ti ++)
+				pldata[ti] = 0;
+			for (x1 = 0; x1 < LOGO_W; x1++) {
+				/* read data */
+				if (!hi_lo) {
+					data = *src >> 4;
+					hi_lo = 1;
+				} else {
+					data = *src & 0xf;
+					src ++;
+					hi_lo = 0;
+				}
+				cpudata |= 1 << (7 - ((x1 + x) & 7));
+				for (ti = 0; ti < 4; ti ++)
+					pldata[ti] |=
+					((data & (1 << ti)) ? (1):(0))
+						<< (7 - ((x1 + x) & 7));
+				if (((x1 + x) & 7) == 7 && cpudata) {
+					for (ti = 0; ti < 4; ti ++)
+						{
+						outb(pldata[ti], 0x7e);
+						pldata[ti] = 0;
+						}
+					dst = fb + y1 * line + ((x1 + x) >> 3);
+					*((char *)dst) = cpudata;
+					cpudata = 0;
+				}
+				/* end */
+			}
+		/* send last data */
+		       if (cpudata) {
+				for (ti = 0; ti < 4; ti ++)
+					outb(pldata[ti], 0x7e);
+				dst = fb + y1 * line + ((x1 + x) >> 3);
+				*dst = cpudata;
+				cpudata = 0;
+			}
+		}
+	/* GRCG OFF */
+	outb(0x00, 0x7c);
+	done = 1;
+	}
+#endif
     }
     
     if (p->fb_info->fbops->fb_rasterimg)
@@ -2452,6 +2859,41 @@
     return done ? (LOGO_H + fontheight(p) - 1) / fontheight(p) : 0 ;
 }
 
+#ifdef CONFIG_PC9800
+static u8 fbcon_attr_at(struct vc_data *con,u8 _color, u8 _intensity,
+			u8 _blink, u8 _underline, u8 _reverse)
+{
+#if 0
+	u8 a = _color;
+	if (_underline)
+		a = (a & 0xf0) | 0x0f;
+	else if (_intensity == 0)
+		a = (a & 0xf0) | 0x08;
+	if (_reverse)
+		a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
+	if (_blink)
+		a ^= 0x80;
+	if (_intensity == 2)
+		a ^= 0x08;
+	return a;
+#else
+	u8 clr = _color;
+	con->vc_pc98_addbuf = 0;
+	if (_intensity > 0)
+		clr |= 0x08;
+	if (_intensity > 1)
+		con->vc_pc98_addbuf |= 0x01; /* bold */
+	if (_underline)
+		con->vc_pc98_addbuf |= 0x02; /* underline */
+	if (_blink)
+		clr |= 0x80;
+	if (_reverse)
+		clr = ((clr << 4) & 0xf0) | ((clr >> 4) & 0x0f);
+	return clr;
+#endif
+}
+#endif
+
 /*
  *  The console `switch' structure for the frame buffer based console
  */
@@ -2472,6 +2914,9 @@
     .con_set_palette = 	fbcon_set_palette,
     .con_scrolldelta = 	fbcon_scrolldelta,
     .con_set_origin = 	fbcon_set_origin,
+#ifdef CONFIG_PC9800
+    .con_build_attr =	fbcon_attr_at,
+#endif
     .con_invert_region = fbcon_invert_region,
     .con_screen_pos =	fbcon_screen_pos,
     .con_getxy =	fbcon_getxy,
diff -urN linux/drivers/video/fbmem.c linux98/drivers/video/fbmem.c
--- linux/drivers/video/fbmem.c	Sun Sep  1 07:04:45 2002
+++ linux98/drivers/video/fbmem.c	Mon Sep  2 15:19:37 2002
@@ -135,6 +135,8 @@
 extern void tx3912fb_setup(char*);
 extern int radeonfb_init(void);
 extern int radeonfb_setup(char*);
+extern int egcfb_init(void);
+extern int egcfb_setup(char*);
 extern int e1355fb_init(void);
 extern int e1355fb_setup(char*);
 extern int pvr2fb_init(void);
@@ -294,6 +296,9 @@
 #ifdef CONFIG_FB_SA1100
 	{ "sa1100", sa1100fb_init, NULL },
 #endif
+#ifdef CONFIG_FB_EGC
+	{ "egc", egcfb_init, egcfb_setup },
+#endif
 #ifdef CONFIG_FB_SUN3
 	{ "sun3", sun3fb_init, sun3fb_setup },
 #endif
@@ -397,6 +402,34 @@
 	if (!info || ! info->screen_base)
 		return -ENODEV;
 
+#ifdef CONFIG_PC9800
+	if (!strcmp(info->fix.id, "egc")) {
+		/* for PC-98x1 VRAM */
+		unsigned long total_copy_size = 0;
+		/* R,G,B plane */
+		if (p < 96*1024) {
+			unsigned long copy_size
+			    = count + p <= 96 * 1024 ? count : 96 * 1024 - p;
+			if (copy_to_user (buf, phys_to_virt(0xA8000+p),
+					  copy_size))
+				return -EFAULT;
+			count -= copy_size;
+			p += copy_size;
+			buf += copy_size;
+			total_copy_size += copy_size;
+		}
+		if(p >= 96*1024 && count > 0) {
+			unsigned long copy_size
+			    = count + p <= 128*1024 ? count : 128*1024 - p;
+			if (copy_to_user(buf,
+					  phys_to_virt(0xE0000 + p - 96*1024),
+					  copy_size))
+				return -EFAULT;
+			total_copy_size += copy_size;
+		}
+		return total_copy_size;
+	}
+#endif
 	if (p >= info->fix.smem_len)
 	    return 0;
 	if (count >= info->fix.smem_len)
@@ -436,6 +469,33 @@
 	    count = info->fix.smem_len - p;
 	    err = -ENOSPC;
 	}
+#ifdef CONFIG_PC9800
+	if (!strcmp(info->fix.id, "egc")) {
+		/* for PC-98x1 VRAM */
+		unsigned long total_copy_size = 0;
+		/* R,G,B plane */
+		if(p < 96*1024) {
+			unsigned long copy_size
+			    = count + p <= 96*1024 ? count : 96*1024 - p;
+			if (copy_from_user(phys_to_virt(0xA8000+p), buf,
+					    copy_size))
+				return -EFAULT;
+			count -= copy_size;
+			p += copy_size;
+			buf += copy_size;
+			total_copy_size += copy_size;
+		}
+		if(p >= 96*1024 && count > 0) {
+			unsigned long copy_size
+			    = count + p <= 128*1024 ? count : 128*1024 - p;
+			if (copy_from_user(phys_to_virt(0xE0000+p-96*1024),
+					    buf, copy_size))
+				return -EFAULT;
+			total_copy_size += copy_size;
+		}
+		return total_copy_size;
+	}
+#endif
 	if (count) {
 	    char *base_addr;
 
diff -urN linux/include/video/fbcon-egc.h linux98/include/video/fbcon-egc.h
--- linux/include/video/fbcon-egc.h	Thu Jan  1 09:00:00 1970
+++ linux98/include/video/fbcon-egc.h	Fri Aug 17 21:50:18 2001
@@ -0,0 +1,32 @@
+/*
+ *	FBcon low-level driver for EGC
+ */
+
+#ifndef _VIDEO_FBCON_EGC_H
+#define _VIDEO_FBCON_EGC_H
+
+#include <linux/config.h>
+
+#ifdef MODULE
+#if defined(CONFIG_FBCON_EGC) || defined(CONFIG_FBCON_EGC_MODULE)
+#define FBCON_HAS_EGC
+#endif
+#else
+#if defined(CONFIG_FBCON_EGC)
+#define FBCON_HAS_EGC
+#endif
+#endif
+
+extern struct display_switch fbcon_egc;
+extern void fbcon_egc_setup(struct display *p);
+extern void fbcon_egc_bmove(struct display *p, int sy, int sx, int dy, int dx,
+				   int height, int width);
+extern void fbcon_egc_clear(struct vc_data *conp, struct display *p, int sy,
+				   int sx, int height, int width);
+extern void fbcon_egc_putc(struct vc_data *conp, struct display *p, int c,
+				  int yy, int xx);
+extern void fbcon_egc_putcs(struct vc_data *conp, struct display *p,
+				   const unsigned short *s, int count, int yy, int xx);
+extern void fbcon_egc_revc(struct display *p, int xx, int yy);
+
+#endif /* _VIDEO_FBCON_EGC_H */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/