diff -urN ../svgalib-1.4.3-orig/src/fbdev.c ./src/fbdev.c
--- ../svgalib-1.4.3-orig/src/fbdev.c	2000-08-28 00:16:06 +0900
+++ src/fbdev.c	2003-09-01 18:36:50 +0900
@@ -1,514 +1,493 @@
-#include <sys/types.h>
+/* Driver for Linux framebuffer
+ * Written by Andrew Church <achurch@achurch.org>
+ * Loosely based on Cirrus driver code.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <linux/fb.h>
-#include <linux/kd.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
 
 #include "vga.h"
 #include "libvga.h"
 #include "driver.h"
 #include "timing.h"
 #include "interface.h"
+#include "vgaregs.h"
+#include "accel.h"
+
+#ifdef BACKGROUND
+# error fbdev does not work with BACKGROUND, please undefine it.
+#endif
+
+/*************************************************************************/
 
-extern unsigned char * B8000_MEM_POINTER;
+/* FD used for framebuffer device (/dev/fbN), -1 = not opened. */
+static int fb_fd = -1;
+
+/* Static information about the framebuffer device. */
+static struct fb_fix_screeninfo fb_fix;
 
-static int fbdev_fd;
-static size_t fbdev_memory;
-static size_t fbdev_startaddressrange;
 static CardSpecs *cardspecs;
-static struct console_font_op fbdev_font;
-static struct fb_var_screeninfo fbdev_textmode;
 
-/* Card Specs */
+static int fbdev_linear_flag = 0;
 
-static int fbdev_match_programmable_clock(int clock)
-{
-	return clock;
-}
+/*************************************************************************/
 
-static int fbdev_map_clock(int bpp, int clock)
-{
-	return clock;
-}
+static int fbdev_test(void);
+static int fbdev_init(int force, int par1, int par2);
+static int fbdev_saveregs(unsigned char regs[]);
+static void fbdev_setregs(const unsigned char regs[], int mode);
+static void fbdev_getmodeinfo(int mode, vga_modeinfo *modeinfo);
+static int fbdev_modeavailable(int mode);
+static int fbdev_setmode(int mode, int prv_mode);
+static void fbdev_unlock(void);
+static void fbdev_lock(void);
+static void fbdev_setpage(int page);
+static void fbdev_setrdpage(int page);
+static void fbdev_setwrpage(int page);
+static void fbdev_setdisplaystart(int address);
+static void fbdev_setlogicalwidth(int width);
+static int fbdev_linear(int op, int param);
+static int fbdev_setpalette(int index, int red, int green, int blue);
+static void fbdev_getpalette(int index, int *red, int *green, int *blue);
+static void fbdev_savepalette(unsigned char *red, unsigned char *green,
+			     unsigned char *blue);
+static void fbdev_restorepalette(const unsigned char *red,
+				 const unsigned char *green,
+				 const unsigned char *blue);
 
-static int fbdev_map_horizontal_crtc(int bpp, int pixelclock, int htiming)
-{
-	return htiming;
-}
+/* Function tables. */
 
-/* Driver Specs */
+static Emulation fbdev_emul = {
+    setpalette: fbdev_setpalette,
+    getpalette: fbdev_getpalette,
+    savepalette: fbdev_savepalette,
+    restorepalette: fbdev_restorepalette,
+};
 
-static int fbdev_saveregs(unsigned char *regs)
+DriverSpecs __svgalib_fbdev_driverspecs =
 {
-	ioctl(fbdev_fd, FBIOGET_VSCREENINFO, regs+EXT);
-	return sizeof(struct fb_var_screeninfo);
-}
+    fbdev_saveregs,
+    fbdev_setregs,
+    fbdev_unlock,
+    fbdev_lock,
+    fbdev_test,
+    fbdev_init,
+    fbdev_setpage,
+    fbdev_setrdpage,
+    fbdev_setwrpage,
+    fbdev_setmode,
+    fbdev_modeavailable,
+    fbdev_setdisplaystart,
+    fbdev_setlogicalwidth,
+    fbdev_getmodeinfo,
+    0,				/* old blit funcs */
+    0,
+    0,
+    0,
+    0,
+    0,				/* ext_set */
+    0,				/* accel */
+    fbdev_linear,
+    NULL,                       /* Accelspecs */
+    &fbdev_emul,                /* Emulation */
+};
 
-static void fbdev_setregs(const unsigned char *regs, int mode)
-{
-	ioctl(fbdev_fd, FBIOPUT_VSCREENINFO, regs+EXT);
-}
 
-static void fbdev_unlock(void)
-{
-}
+/*************************************************************************/
+/*************************************************************************/
 
-static void fbdev_lock(void)
+/* Test for the presence of the framebuffer device.  If found, initialize
+ * and return 1, else return 0.
+ */
+
+static int fbdev_test(void)
 {
+    fb_fd = open("/dev/fb0", O_RDONLY);
+    if (fb_fd < 0) {
+	if (errno == EPERM) {
+	    fprintf(stderr, "svgalib(fbdev): Permission denied on framebuffer device.\n");
+	    exit(1);
+	}
+	return 0;
+    }
+    return !fbdev_init(0,0,0);
 }
 
-static int fbdev_init(int force, int par1, int par2)
-{
-	struct fb_fix_screeninfo info;
-	int fd;
+/*************************************************************************/
 
-	if ((fd = open("/dev/fb0", O_RDWR)) < 0)
-	{
-		return -1;
-	}
+/* Initialize the framebuffer device. */
 
-	if (ioctl(fd, FBIOGET_FSCREENINFO, &info))
-	{
-		close(fd);
-		return -1;
-	}
+static int fbdev_mapClock(int bpp, int pixelclock);
+static int fbdev_matchProgrammableClock(int desiredclock);
+static int fbdev_mapHorizontalCrtc(int bpp, int pixelclock, int htiming);
 
-	if (ioctl(fd, FBIOGET_VSCREENINFO, &fbdev_textmode))
-	{
-		close(fd);
-		return -1;
-	}
+static int fbdev_init(int force, int par1, int par2)
+{
+    if (fb_fd < 0 && !fbdev_test())
+	return -1;
+    if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fb_fix) < 0)
+	return -1;
 
-	fbdev_memory = info.smem_len;
-	fbdev_fd = fd;
+    __svgalib_novga = 1;   /* No user-serviceable parts inside */
 
-	fbdev_startaddressrange = 65536;
-	while (fbdev_startaddressrange < fbdev_memory)
-	{
-		fbdev_startaddressrange <<= 1;
-	}
-	fbdev_startaddressrange -= 1;
+    cardspecs = malloc(sizeof(CardSpecs));
+    cardspecs->videoMemory = fb_fix.smem_len;
+    /* The kernel takes care of clock setting, so put bogus values here */
+    cardspecs->maxPixelClock4bpp = 999999;
+    cardspecs->maxPixelClock8bpp = 999999;
+    cardspecs->maxPixelClock16bpp = 999999;
+    cardspecs->maxPixelClock24bpp = 999999;
+    cardspecs->maxPixelClock32bpp = 999999;
+    cardspecs->nClocks = 0;
+    cardspecs->flags = CLOCK_PROGRAMMABLE;
+    cardspecs->mapClock = fbdev_mapClock;
+    cardspecs->matchProgrammableClock = fbdev_matchProgrammableClock;
+    cardspecs->mapHorizontalCrtc = fbdev_mapHorizontalCrtc;
+    cardspecs->maxHorizontalCrtc = 65535;
 
-	cardspecs = malloc(sizeof(CardSpecs));
-	cardspecs->videoMemory = fbdev_memory;
+    __svgalib_fbdev_driverspecs.accelspecs = malloc(sizeof(AccelSpecs));
+    __svgalib_clear_accelspecs(__svgalib_fbdev_driverspecs.accelspecs);
+    __svgalib_fbdev_driverspecs.accelspecs->flags = ACCELERATE_ANY_LINEWIDTH;
 
-/* FIXME: autodetect these */
-	cardspecs->maxPixelClock4bpp = 200000;
-	cardspecs->maxPixelClock8bpp = 200000;
-	cardspecs->maxPixelClock16bpp = 200000;
-	cardspecs->maxPixelClock24bpp = 200000;
-	cardspecs->maxPixelClock32bpp = 200000;
-	cardspecs->maxHorizontalCrtc = 8192;
-
-	cardspecs->flags = CLOCK_PROGRAMMABLE;
-
-	cardspecs->nClocks = 0;
-	cardspecs->clocks = 0;
-
-	cardspecs->mapClock = fbdev_map_clock;
-	cardspecs->matchProgrammableClock = fbdev_match_programmable_clock;
-	cardspecs->mapHorizontalCrtc = fbdev_map_horizontal_crtc;
-
-	__svgalib_driverspecs = &__svgalib_fbdev_driverspecs;
-	__svgalib_banked_mem_base = info.smem_start;
-	__svgalib_banked_mem_size = 0x10000;
-	__svgalib_linear_mem_base = info.smem_start;
-	__svgalib_linear_mem_size = fbdev_memory;
-
-	__svgalib_novga = 1;
-	B8000_MEM_POINTER = (void *)0xB8000;
-	BANKED_MEM_POINTER = mmap(0, __svgalib_banked_mem_size,
-				  PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-	LINEAR_MEM_POINTER = mmap(0, __svgalib_linear_mem_size,
-				  PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    __svgalib_driverspecs = &__svgalib_fbdev_driverspecs;
 
-	return 0;
+    __svgalib_banked_mem_base = fb_fix.smem_start;
+    __svgalib_banked_mem_size = 0x10000;
+    __svgalib_linear_mem_base = fb_fix.smem_start;
+    __svgalib_linear_mem_size = fb_fix.smem_len;
+    __svgalib_mmio_size = 0;
+    __svgalib_mmio_base = 0;
+    return 0;
 }
 
-static int fbdev_test(void)
-{
-	return !fbdev_init(0, 0, 0);
+static int fbdev_mapClock(int bpp, int pixelclock) {
+    return pixelclock;
 }
 
-static void fbdev_setpage(int page)
-{
-	static int oldpage = 0;
-
-	if (page != oldpage)
-	{
-//		munmap(BANKED_MEM_POINTER, __svgalib_banked_mem_size);
-		mmap(BANKED_MEM_POINTER, __svgalib_banked_mem_size,
-		     PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED,
-		     fbdev_fd, page * __svgalib_banked_mem_size);
-		oldpage = page;
-	}
+static int fbdev_matchProgrammableClock(int desiredclock) {
+    return desiredclock;
 }
 
-static int fbdev_screeninfo(struct fb_var_screeninfo *info, int mode)
-{
-	ModeTiming modetiming;
-	ModeInfo *modeinfo;
-
-	/* The VGA modes don't work */
-
-	if ((mode < G640x480x256 ) || mode == G720x348x2)
-		return 1;
+static int fbdev_mapHorizontalCrtc(int bpp, int pixelclock, int htiming) {
+    return htiming;
+}
 
-	if (ioctl(fbdev_fd, FBIOGET_VSCREENINFO, info))
-		return 1;
+/*************************************************************************/
 
-	modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode);
+/* Read and save chipset-specific registers */
 
-	if (__svgalib_getmodetiming(&modetiming, modeinfo, cardspecs))
-	{
-		free(modeinfo);
-		return 1;
-	}
+static int fbdev_saveregs(unsigned char regs[])
+{
+    ioctl(fb_fd, FBIOGET_VSCREENINFO, &regs[VGA_TOTAL_REGS]);
+    return sizeof(struct fb_var_screeninfo);
+}
 
-	info->xres = modeinfo->width;
-	info->yres = modeinfo->height;
-	info->xres_virtual = modeinfo->width;
-	info->yres_virtual = modeinfo->height;
-	info->xoffset = 0;
-	info->yoffset = 0;
-	info->bits_per_pixel = modeinfo->bitsPerPixel;
-	info->grayscale = 0;
-	info->red.offset = modeinfo->redOffset;
-	info->red.length = modeinfo->redWeight;
-	info->red.msb_right = 0;
-	info->green.offset = modeinfo->greenOffset;
-	info->green.length = modeinfo->greenWeight;
-	info->green.msb_right = 0;
-	info->blue.offset = modeinfo->blueOffset;
-	info->blue.length = modeinfo->blueWeight;
-	info->blue.msb_right = 0;
-	info->nonstd = 0;
-
-	free(modeinfo);
-
-	info->vmode &= FB_VMODE_MASK;
-
-	if (modetiming.flags & INTERLACED)
-		info->vmode |= FB_VMODE_INTERLACED;
-	if (modetiming.flags & DOUBLESCAN)
-	{
-		info->vmode |= FB_VMODE_DOUBLE;
-		modetiming.VDisplay >>= 1;
-		modetiming.VSyncStart >>= 1;
-		modetiming.VSyncEnd >>= 1;
-		modetiming.VTotal >>= 1;
-	}
+/*************************************************************************/
 
-	info->pixclock = 1000000000 / modetiming.pixelClock;
-	info->left_margin = modetiming.HTotal - modetiming.HSyncEnd;
-	info->right_margin = modetiming.HSyncStart - modetiming.HDisplay;
-	info->upper_margin = modetiming.VTotal - modetiming.VSyncEnd;
-	info->lower_margin = modetiming.VSyncStart - modetiming.VDisplay;
-	info->hsync_len = modetiming.HSyncEnd - modetiming.HSyncStart;
-	info->vsync_len = modetiming.VSyncEnd - modetiming.VSyncStart;
-
-	info->sync &= ~(FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT);
-
-	if (modetiming.flags & PHSYNC)
-		info->sync |= FB_SYNC_HOR_HIGH_ACT;
-	if (modetiming.flags & PVSYNC)
-		info->sync |= FB_SYNC_VERT_HIGH_ACT;
+/* Set chipset-specific registers */
 
-	return 0;
+static void fbdev_setregs(const unsigned char regs[], int mode)
+{
+    struct fb_var_screeninfo *fb_var =
+	(struct fb_var_screeninfo *) &regs[VGA_TOTAL_REGS];
+    fb_var->activate = FB_ACTIVATE_NOW;
+    ioctl(fb_fd, FBIOPUT_VSCREENINFO, fb_var);
 }
 
-static void fbdev_set_virtual_height(struct fb_var_screeninfo *info)
-{
-	int maxpixels = fbdev_memory;
-	int bytesperpixel = info->bits_per_pixel / 8;
- 
-	if (bytesperpixel)
-		maxpixels /= bytesperpixel;
+/*************************************************************************/
 
-	info->yres_virtual = maxpixels / info->xres_virtual;
-}
+/* Fill in chipset specific mode information */
 
-static int fbdev_setmode(int mode, int prv_mode)
+static void fbdev_getmodeinfo(int mode, vga_modeinfo *modeinfo)
 {
-	struct fb_var_screeninfo info;
+    if (modeinfo->bytesperpixel > 0)
+	modeinfo->maxpixels = fb_fix.smem_len / modeinfo->bytesperpixel;
+    else  /* 16-color mode */
+	modeinfo->maxpixels = fb_fix.smem_len * 2;
+    modeinfo->maxlogicalwidth = 65535;
+    modeinfo->startaddressrange = fb_fix.smem_len * 1024 - 1;
+    modeinfo->haveblit = 0;
+#if 0				/* Who cares. */
+    if (fbdev_interlaced(mode))
+	modeinfo->flags |= IS_INTERLACED;
+#endif
+    modeinfo->flags &= ~HAVE_RWPAGE;
+    modeinfo->flags |= CAPABLE_LINEAR | fbdev_linear_flag;
+}
 
-	if (mode == TEXT)
-	{
-		if (ioctl(fbdev_fd, FBIOPUT_VSCREENINFO, &fbdev_textmode))
-			return 1;
-
-		memset(LINEAR_MEM_POINTER, 0,
-		       fbdev_textmode.bits_per_pixel ?
-		       fbdev_textmode.xres_virtual *
-		       fbdev_textmode.yres_virtual *
-		       fbdev_textmode.bits_per_pixel / 8 : 65536);
-	}
-	else
-	{
-		if (fbdev_screeninfo(&info, mode))
-			return 1;
+/*************************************************************************/
 
-		fbdev_set_virtual_height(&info);
+/* Return nonzero if mode is available */
 
-		if (ioctl(fbdev_fd, FBIOPUT_VSCREENINFO, &info))
-			return 1;
-	}
+static int fbdev_modeavailable(int mode)
+{
+    struct info *info;
 
+    info = &__svgalib_infotable[mode];
+    if (fb_fix.smem_len < info->ydim * info->xbytes)
 	return 0;
+    return SVGADRV;
 }
 
-static int fbdev_modeavailable(int mode)
-{
-	struct fb_var_screeninfo info;
-	unsigned g;
-
-	if (fbdev_screeninfo(&info, mode))
-		return 0;
+/*************************************************************************/
+/*************************************************************************/
 
-	g = info.green.length;
+/* Set a mode.  Returns 0 on success, 1 on failure. */
 
-	info.activate = FB_ACTIVATE_TEST;
-	if (ioctl(fbdev_fd, FBIOPUT_VSCREENINFO, &info))
-		return 0;
+static int fbdev_real_setmode(ModeTiming *modetiming, ModeInfo *modeinfo);
 
-	if (info.bits_per_pixel == 16 &&
-	    info.green.length != g)
-		return 0;
+static int fbdev_setmode(int mode, int prv_mode)
+{
+    ModeTiming modetiming;
+    ModeInfo *modeinfo;
+    int n = 999999, lastclock = -1;
+
+    if (!fbdev_modeavailable(mode))
+	return 1;
+
+    modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode);
+
+    for (;;) {
+	/* Abort if our temporary max pixel clock (see below) drops
+	 * below 5MHz. */
+	if (cardspecs->maxPixelClock8bpp < 5000
+	 || __svgalib_getmodetiming(&modetiming, modeinfo, cardspecs)
+	) {
+	    free(modeinfo);
+	    cardspecs->maxPixelClock4bpp = 999999;
+	    cardspecs->maxPixelClock8bpp = 999999;
+	    cardspecs->maxPixelClock16bpp = 999999;
+	    cardspecs->maxPixelClock24bpp = 999999;
+	    cardspecs->maxPixelClock32bpp = 999999;
+	    return 1;
+	}
+/*printf("fbdev: got timing for mode %dx%d-%d:\n%d %d %d %d %d %d %d %d %d\n",
+modeinfo->width,modeinfo->height,modeinfo->bitsPerPixel,modetiming.pixelClock,
+modetiming.HDisplay,modetiming.HSyncStart,modetiming.HSyncEnd,modetiming.HTotal,
+modetiming.VDisplay,modetiming.VSyncStart,modetiming.VSyncEnd,modetiming.VTotal);*/
+	if (fbdev_real_setmode(&modetiming, modeinfo)) {
+	    /* We were able to set the mode */
+	    cardspecs->maxPixelClock4bpp = 999999;
+	    cardspecs->maxPixelClock8bpp = 999999;
+	    cardspecs->maxPixelClock16bpp = 999999;
+	    cardspecs->maxPixelClock24bpp = 999999;
+	    cardspecs->maxPixelClock32bpp = 999999;
+	    break;
+	}
+	/* Temporarily redefine maximum pixel clock to make getmodetiming()
+	 * give us the next best mode available.  If we got back the same
+	 * clock as last time, cut the previous value down further (avoid
+	 * infinite loops). */
+	if (modetiming.pixelClock != lastclock)
+	    n = modetiming.pixelClock;
+	n = n*989 / 1000;
+	cardspecs->maxPixelClock4bpp = n;
+	cardspecs->maxPixelClock8bpp = n;
+	cardspecs->maxPixelClock16bpp = n;
+	cardspecs->maxPixelClock24bpp = n;
+	cardspecs->maxPixelClock32bpp = n;
+    }
+
+    __svgalib_InitializeAcceleratorInterface(modeinfo);
+
+    free(modeinfo);
+    return 0;
+}
+
+/*************************************************************************/
+
+/* Attempt to actually set the specified mode.  Return 1 on success, 0 on
+ * failure.
+ */
+
+static int fbdev_real_setmode(ModeTiming *modetiming, ModeInfo *modeinfo)
+{
+    struct fb_var_screeninfo var;
+    int res;
+
+    memset(&var, 0, sizeof(var));
+    var.xres           = modeinfo->width;
+    var.yres           = modeinfo->height;
+    var.xres_virtual   = modeinfo->width;
+    var.yres_virtual   = modeinfo->height;
+    var.bits_per_pixel = modeinfo->bitsPerPixel;
+    var.red  .offset   = modeinfo->redOffset;
+    var.red  .length   = modeinfo->redWeight;
+    var.green.offset   = modeinfo->greenOffset;
+    var.green.length   = modeinfo->greenWeight;
+    var.blue .offset   = modeinfo->blueOffset;
+    var.blue .length   = modeinfo->blueWeight;
+    var.height         = modeinfo->height;    /* FIXME: Are these 2 correct? */
+    var.width          = modeinfo->lineWidth;
+    var.pixclock       = 1000000000 / modetiming->pixelClock; /* picoseconds */
+    var.left_margin    = modetiming->HTotal - modetiming->HSyncEnd;
+    var.right_margin   = modetiming->HSyncStart - modetiming->HDisplay;
+    var.upper_margin   = modetiming->VTotal - modetiming->VSyncEnd;
+    var.lower_margin   = modetiming->VSyncStart - modetiming->VDisplay;
+    var.hsync_len      = modetiming->HSyncEnd - modetiming->HSyncStart;
+    var.vsync_len      = modetiming->VSyncEnd - modetiming->VSyncStart;
+    if (modetiming->flags & PHSYNC)
+	var.sync      |= FB_SYNC_HOR_HIGH_ACT;
+    if (modetiming->flags & PVSYNC)
+	var.sync      |= FB_SYNC_VERT_HIGH_ACT;
+    if (modetiming->flags & INTERLACED)
+	var.vmode      = FB_VMODE_INTERLACED;
+    else if (modetiming->flags & DOUBLESCAN) {
+	var.vmode      = FB_VMODE_DOUBLE;
+	var.upper_margin >>= 1;
+	var.lower_margin >>= 1;
+	var.vsync_len    >>= 1;
+    }
+
+    res = ioctl(fb_fd, FBIOPUT_VSCREENINFO, &var);
+/*printf("put_var: res=%d (%s)\n",res,strerror(errno));*/
+    return res == 0;
+}
 
-	/* We may need to add more checks here. */
+/*************************************************************************/
+/*************************************************************************/
 
-	return SVGADRV;
-}
+/* Unlock chipset-specific registers (not used by fbdev) */
 
-static void fbdev_setdisplaystart(int address)
+static void fbdev_unlock(void)
 {
-	struct fb_var_screeninfo info;
-
-	if (ioctl(fbdev_fd, FBIOGET_VSCREENINFO, &info))
-		return;
+}
 
-	info.xoffset = address % info.xres_virtual;
-	info.yoffset = address / info.xres_virtual;
+/*************************************************************************/
 
-	ioctl(fbdev_fd, FBIOPAN_DISPLAY, &info);
-}
+/* Relock chipset-specific registers (not used by fbdev) */
 
-static void fbdev_setlogicalwidth(int width)
+static void fbdev_lock(void)
 {
-	struct fb_var_screeninfo info;
+}
 
-	if (ioctl(fbdev_fd, FBIOGET_VSCREENINFO, &info))
-		return;
+/*************************************************************************/
 
-	info.xres_virtual = width;
-	fbdev_set_virtual_height(&info);
+/* Bank switching functions.
+ * fbdev does not use rdpage and wrpage.  setpage is emulated by changing
+ * __svgalib_graph_mem to point at the appropriate part of the framebuffer
+ * memory, which may or may not be entirely safe.
+ */
 
-	ioctl(fbdev_fd, FBIOPUT_VSCREENINFO, &info);
+static void fbdev_setpage(int page)
+{
+    __svgalib_graph_mem = LINEAR_MEM_POINTER + (page<<16);
 }
 
-static void fbdev_getmodeinfo(int mode, vga_modeinfo * modeinfo)
+static void fbdev_setrdpage(int page)
 {
-	struct fb_var_screeninfo info;
-	int maxpixels = fbdev_memory;
-
-	if (modeinfo->bytesperpixel)
-		maxpixels /= modeinfo->bytesperpixel;
-
-	modeinfo->maxlogicalwidth = maxpixels / modeinfo->height;
-	modeinfo->startaddressrange = fbdev_startaddressrange;
-	modeinfo->maxpixels = maxpixels;
-	modeinfo->haveblit = 0;
-	modeinfo->flags |= (__svgalib_modeinfo_linearset | CAPABLE_LINEAR); 
-
-	if (fbdev_screeninfo(&info, mode))
-		return;
-
-	info.activate = FB_ACTIVATE_TEST;
-	if (ioctl(fbdev_fd, FBIOPUT_VSCREENINFO, &info))
-		return;
-
-	modeinfo->linewidth = info.xres_virtual * info.bits_per_pixel / 8;
 }
 
-static int fbdev_linear(int op, int param)
+static void fbdev_setwrpage(int page)
 {
-	switch(op)
-	{
-	case LINEAR_QUERY_BASE:
-		return __svgalib_linear_mem_base;
-	case LINEAR_ENABLE:
-	case LINEAR_DISABLE:
-		return 0;
-	}
-	return -1;
 }
 
-/* Emulation */
+/*************************************************************************/
 
-static void fbdev_savepalette(unsigned char *red,
-			unsigned char *green,
-			unsigned char *blue)
-{
-	__u16 r[256], g[256], b[256], t[256];
-	struct fb_cmap cmap;
-	unsigned i;
-
-	cmap.start = 0;
-	cmap.len = 256;
-	cmap.red = r;
-	cmap.green = g;
-	cmap.blue = b;
-	cmap.transp = t;
-
-	if (ioctl(fbdev_fd, FBIOGETCMAP, &cmap))
-		return;
-
-	for (i = 0; i < 256; i++)
-	{
-		red[i] = r[i] >> 10;
-		green[i] = g[i] >> 10;
-		blue[i] = b[i] >> 10;
-	}
-}
+/* Set display start address (not for 16 color modes) */
+/* fbdev currently only allows Y scrolling */
 
-static void fbdev_restorepalette(const unsigned char *red,
-			   const unsigned char *green,
-			   const unsigned char *blue)
+static void fbdev_setdisplaystart(int address)
 {
-	__u16 r[256], g[256], b[256], t[256];
-	struct fb_cmap cmap;
-	unsigned i;
-
-	for (i = 0; i < 256; i++)
-	{
-		r[i] = (red[i] << 10) | (red[i] << 4) | (red[i] >> 2);
-		g[i] = (green[i] << 10) | (green[i] << 4) | (green[i] >> 2);
-		b[i] = (blue[i] << 10) | (blue[i] << 4) | (blue[i] >> 2);
-		t[i] = 0;
-	}
+    struct fb_var_screeninfo var;
+    int yoffset;
 
-	cmap.start = 0;
-	cmap.len = 256;
-	cmap.red = r;
-	cmap.green = g;
-	cmap.blue = b;
-	cmap.transp = t;
-
-	ioctl(fbdev_fd, FBIOPUTCMAP, &cmap);
+    if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &var) < 0)
+	return;
+    yoffset = address / (var.xres_virtual * var.bits_per_pixel / 8);
+    ioctl(fb_fd, FBIOPAN_DISPLAY, 0, yoffset);
 }
 
-static int fbdev_setpalette(int index, int red, int green, int blue)
-{
-	__u16 r, g, b, t;
-	struct fb_cmap cmap;
-
-	r = (red << 10) | (red << 4) | (red >> 2);
-	g = (green << 10) | (green << 4) | (green >> 2);
-	b = (blue << 10) | (blue << 4) | (blue >> 2);
-	t = 0;
-
-	cmap.start = index;
-	cmap.len = 1;
-	cmap.red = &r;
-	cmap.green = &g;
-	cmap.blue = &b;
-	cmap.transp = &t;
-	ioctl(fbdev_fd, FBIOPUTCMAP, &cmap);
+/*************************************************************************/
 
-	return 0;
-}
+/* Set logical scanline length (usually multiple of 8) */
+/* Not currently supported by fbdev */
 
-static void fbdev_getpalette(int index, int *red, int *green, int *blue)
+static void fbdev_setlogicalwidth(int width)
 {
-	__u16 r, g, b, t;
-	struct fb_cmap cmap;
+}
 
-	cmap.start = 0;
-	cmap.len = 1;
-	cmap.red = &r;
-	cmap.green = &g;
-	cmap.blue = &b;
-	cmap.transp = &t;
+/*************************************************************************/
 
-	if (ioctl(fbdev_fd, FBIOGETCMAP, &cmap))
-		return;
+/* Set/query linear mode. */
 
-	*red = r >> 10;
-	*green = g >> 10;
-	*blue = b >> 10;
+static int fbdev_linear(int op, int param)
+{
+    if (op == LINEAR_ENABLE) {
+	fbdev_linear_flag = IS_LINEAR;
+	return 0;
+    }
+    if (op == LINEAR_DISABLE) {
+	fbdev_linear_flag = 0;
+	return 0;
+    }
+    if (op == LINEAR_QUERY_BASE)
+	return fb_fix.smem_start;
+    if (op == LINEAR_QUERY_RANGE || op == LINEAR_QUERY_GRANULARITY)
+	return 0;		/* No granularity or range. */
+    else
+	return -1;		/* Unknown function. */
 }
 
-static void fbdev_savefont(void)
+/*************************************************************************/
+/*************************************************************************/
+
+static int fbdev_setpalette(int index, int red, int green, int blue)
 {
-	fbdev_font.op = KD_FONT_OP_GET;
-	fbdev_font.flags = 0;
-	fbdev_font.width = 32;
-	fbdev_font.height = 32;
-	fbdev_font.charcount = 512;
-	fbdev_font.data = malloc(65536);
+    struct fb_cmap cmap;
+    __u16 red16, green16, blue16;
 
-	ioctl(fbdev_fd, KDFONTOP, &fbdev_font);
+    red16 = red<<10;
+    green16 = green<<10;
+    blue16 = blue<<10;
+    cmap.start = index;
+    cmap.len = 1;
+    cmap.red = &red16;
+    cmap.green = &green16;
+    cmap.blue = &blue16;
+    cmap.transp = NULL;
+    return ioctl(fb_fd, FBIOPUTCMAP, &cmap);
 }
 
-static void fbdev_restorefont(void)
+/*************************************************************************/
+
+static void fbdev_getpalette(int index, int *red, int *green, int *blue)
 {
-	struct fb_var_screeninfo info;
+    struct fb_cmap cmap;
+    __u16 red16 = 0, green16 = 0, blue16 = 0;
 
-	fbdev_font.op = KD_FONT_OP_SET;
-	ioctl(fbdev_fd, KDFONTOP, &fbdev_font);
+    cmap.start = index;
+    cmap.len = 1;
+    cmap.red = &red16;
+    cmap.green = &green16;
+    cmap.blue = &blue16;
+    cmap.transp = NULL;
+    ioctl(fb_fd, FBIOGETCMAP, &cmap);
+    *red = red16>>10;
+    *green = green16>>10;
+    *blue = blue16>>10;
 }
 
-static void fbdev_waitretrace(void)
+/*************************************************************************/
+
+static void fbdev_savepalette(unsigned char *red, unsigned char *green,
+			     unsigned char *blue)
 {
-	/* This is from SDL */
-#ifdef FBIOWAITRETRACE
-	ioctl(console_fd, FBIOWAITRETRACE, 0);
-#endif
 }
 
-/* Function tables */
+/*************************************************************************/
 
-static Emulation fbdev_vgaemul = 
+static void fbdev_restorepalette(const unsigned char *red,
+				 const unsigned char *green,
+				 const unsigned char *blue)
 {
-	fbdev_savepalette,
-	fbdev_restorepalette,
-	fbdev_setpalette,
-	fbdev_getpalette,
-	fbdev_savefont,
-	fbdev_restorefont,
-	0,				/* screenoff */
-	0,				/* screenon */
-	fbdev_waitretrace
-};
+}
 
-DriverSpecs __svgalib_fbdev_driverspecs =
-{
-	fbdev_saveregs,
-	fbdev_setregs,
-	fbdev_unlock,
-	fbdev_lock,
-	fbdev_test,
-	fbdev_init,
-	fbdev_setpage,
-	0,				/* setrdpage */
-	0,				/* setwrpage */
-	fbdev_setmode,
-	fbdev_modeavailable,
-	fbdev_setdisplaystart,
-	fbdev_setlogicalwidth,
-	fbdev_getmodeinfo,
-	0,				/* bitblt */
-	0,				/* imageblt */
-	0,				/* fillblt */
-	0,				/* hlinelistblt */
-	0,				/* bltwait */
-	0,				/* extset */
-	0,				/* accel */
-	fbdev_linear,
-	0,				/* Accelspecs */
-	&fbdev_vgaemul
-};
+/*************************************************************************/
diff -urN ../svgalib-1.4.3-orig/src/vga.c ./src/vga.c
--- ../svgalib-1.4.3-orig/src/vga.c	2001-05-29 23:37:55 +0900
+++ src/vga.c	2003-09-01 18:38:15 +0900
@@ -720,7 +720,7 @@
 "I740",
 "NEOMAGIC",
 "LAGUNA",
-"FBDev",
+"FBDEV",
 "G400",
 "R128",
 "Savage",
@@ -837,8 +837,8 @@
 #endif
 #endif
 
-    if (CHIPSET == FBDEV)
-	return;
+//    if (CHIPSET == FBDEV)
+//	return;
 
     /*  Ensure that the open will get a file descriptor greater
      *  than 2, else problems can occur with stdio functions
@@ -1491,6 +1491,11 @@
 	    CHIPSET = ALI;
 	else
 #endif
+#ifdef INCLUDE_FBDEV_DRIVER_TEST
+	if (__svgalib_fbdev_driverspecs.test())
+	    CHIPSET = FBDEV;
+	else
+#endif
 #ifdef INCLUDE_APM_DRIVER_TEST
 /* Note: On certain cards this may toggle the video signal on/off which
    is ugly. Hence we test this last. */
@@ -2212,6 +2217,7 @@
 int vga_setmode(int mode)
 {
     int modeflags=mode&0xfffff000;
+    int i;
     
     if(mode==-1)return vga_version;
     
@@ -2385,7 +2391,8 @@
         if (!__svgalib_secondary)
 	    ioctl(__svgalib_tty_fd, KDSETMODE, KD_GRAPHICS);
 
-	if (SVGAMODE(prv_mode)) {
+	/* Not needed for fbdev --achurch */
+	if (SVGAMODE(prv_mode) && CHIPSET != FBDEV) {
 	    /* The current mode is an SVGA mode, and we now want to */
 	    /* set a standard VGA mode. Make sure the extended regs */
 	    /* are restored. */
@@ -2404,7 +2411,16 @@
 	CI.xbytes = infotable[mode].xbytes;
 	CI.bytesperpixel = infotable[mode].bytesperpixel;
 
-	chipset_setmode(mode, prv_mode);
+	/* With the fbdev driver, we don't know whether we can set a mode
+	 * until we actually try to do so.  Check the return value of
+	 * chipset_setmode and abort as needed.
+	 * We really should do that for all chipsets, but when actually
+	 * banging the hardware some additional adjustments may be
+	 * necessary.  These are left as an exercise for the reader. --achurch
+	 */
+	i = chipset_setmode(mode, prv_mode);
+	if (CHIPSET == FBDEV && i != 0)
+	    return -1;
 	MODEX = 0;
 
 	/* Set default claimed memory (moved here from initialize - Michael.) */
@@ -2575,7 +2591,8 @@
     modeinfo.flags &= modeinfo_mask;
 
     /* Many cards have problems with linear 320x200x256 mode */
-    if(mode==G320x200x256)modeinfo.flags &= (~CAPABLE_LINEAR) & (~IS_LINEAR) ;
+    if(mode==G320x200x256 && CHIPSET != FBDEV)
+	modeinfo.flags &= (~CAPABLE_LINEAR) & (~IS_LINEAR) ;
 
     /* If all needed info is here, signal if linear support has been enabled */
     if ((modeinfo.flags & (CAPABLE_LINEAR | EXT_INFO_AVAILABLE)) ==
