2nd version: graphic framebuffer for ia32

Gerd Knorr (kraxel@goldbach.isdn.cs.tu-berlin.de)
Sat, 16 May 1998 13:45:04 +0200 (MEST)


Hi !

Here is a _much_ improved version of the graphic framebuffer patch for
intel boxes. diff is against vger's CVS tree (two days old checkout).

What it does
============

Idea is simple: Turn on graphics mode at boot time and use this as
framebuffer device /dev/fb0, like the m68k (and other) ports do. I use
the VESA BIOS Extentions for this purpose. Version 2.0 is required
for linear frame buffer support.

This means we decide at boot time whenever we want to run in text or
graphics mode. Switching mode later on (in protected mode) is impossible
for obvious reasons.

How to use it
=============

Take a vger CVS checkout, apply the patch, reconfigure the kernel. You
have to enable CONFIG_ABSTRACT_CONSOLE, CONFIG_FB, CONFIG_FB_VGA and
CONFIG_FB_VESA.

Switching modes is done using the vga=... boot parameter. Read
Documentation/svga.txt for details. Your new kernel works exactly as
documented there, except for the fact that you can pass mode
numbers for VESA graphic modes too. Text modes are handled by vgafb,
graphic modes by the new vesafb.c.

The graphic modes are not in the list which you get if you boot with
vga=ask and hit return. Here are some mode numbers:

0x101 640x480x8 (you have to type in 301 at the prompt, or boot
with vga=769. Remember: lilo can't handle hex..)
0x103 800x600x8
0x105 1024x768x8
0x107 1280x1024x8 (starts getting unreadable on a 17" screen...)

0x113 800x600x15
0x114 800x600x16
0x115 800x600x32
0x116-8 1024x768x...

What works?
===========

8 bit color modes work fine. You'll get a nice boot logo like on other
architectures with a graphical frame buffer. You can run XF68_FBDev[1].
XF86_SVGA can handle the new situation (console in graphic mode) too, at
least with my card.
Colormap programming is done by accessing the vga dac registers directly
(remember: no bios), so you might run in touble if your board is'nt vga
register compatible.

With 15/16 bit color depth you get at least a working console. XF68_FBDev
does not work for me (black screen), but this might be becauce the Server
can't handle this (according to the man-page TrueColor support is
incomplete). The boot logo colors are wrong, guess there are some endian
issues in the fbcon driver, althrouth I hav'nt checked yet.

With 32bit I see the boot logo (wrong colors too), the white, flashing
cursor, but no text. Hav'nt even tried XF68_FBDev.

Additional hints
================

Turn on write-combining for the framebuffer using /proc/mtrr, this speeds
up scrolling alot.

Going to a friend's bithday party now,

Gerd

[1] Beside some minor keyboard problems, XF68_FBDev (the version included
in XFree 3.3.2 compiles and runs out of the box. The only thing you
have to to is to edit xf86site.cf and enable it, becauce XF68_FBDev
is'nt build by default on linux/ia32.

patch follows...
--------------------------------------------------------------------------
diff -urN /data/vger-cvs/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S
--- /data/vger-cvs/linux/arch/i386/boot/video.S Thu Apr 2 12:42:35 1998
+++ linux/arch/i386/boot/video.S Fri May 15 15:51:13 1998
@@ -77,6 +77,14 @@
#define PARAM_HAVE_VGA 15
#define PARAM_FONT_POINTS 16

+#define PARAM_LFB_WIDTH 18
+#define PARAM_LFB_HEIGHT 20
+#define PARAM_LFB_DEPTH 22
+#define PARAM_LFB_BASE 24
+#define PARAM_LFB_SIZE 28
+#define PARAM_LFB_LINELENGTH 32
+#define PARAM_LFB_COLORS 34
+
! Define DO_STORE according to CONFIG_VIDEO_RETAIN
#ifdef CONFIG_VIDEO_RETAIN
#define DO_STORE call store_screen
@@ -155,6 +163,9 @@
!

mode_params:
+ cmpb [graphic_mode],#0
+ jnz mopar_gr
+
mov ah,#0x03 ! Read cursor position
xor bh,bh
int 0x10
@@ -194,6 +205,46 @@
movb [PARAM_VIDEO_LINES],al
ret

+mopar_gr:
+ lea di,modelist+1024
+ seg fs
+ movb [PARAM_HAVE_VGA],#0x23
+
+ mov ax,(di+16)
+ seg fs
+ mov [PARAM_LFB_LINELENGTH],ax
+
+ mov ax,(di+18)
+ seg fs
+ mov [PARAM_LFB_WIDTH],ax
+
+ mov ax,(di+20)
+ seg fs
+ mov [PARAM_LFB_HEIGHT],ax
+
+ mov al,(di+25)
+ mov ah,#0
+ seg fs
+ mov [PARAM_LFB_DEPTH],ax
+
+ mov eax,(di+40)
+ seg fs
+ mov [PARAM_LFB_BASE],eax
+
+ mov eax,(di+44)
+ seg fs
+ mov [PARAM_LFB_SIZE],eax
+
+ mov eax,(di+31)
+ seg fs
+ mov [PARAM_LFB_COLORS],eax
+
+ mov eax,(di+35)
+ seg fs
+ mov [PARAM_LFB_COLORS+4],eax
+
+ ret
+
#ifdef CONFIG_VIDEO_SELECT

!
@@ -355,7 +406,8 @@
stc
ret

-_setrec: br setrec ! Ugly...
+_setrec: br setrec ! Ugly...
+_set_80x25: br set_80x25

!
! Aliases for backward compatibility.
@@ -388,7 +440,7 @@
cmp ah,#VIDEO_FIRST_V7>>8
jz setv7
cmp ah,#VIDEO_FIRST_VESA>>8
- jnc setvesa
+ jnc check_vesa
or ah,ah
jz setmenu
dec ah
@@ -427,7 +479,7 @@

setmenu:
or al,al ! 80x25 is an exception
- jz set_80x25
+ jz _set_80x25
push bx ! Set mode chosen from menu
call mode_table ! Build the mode table
pop ax
@@ -452,6 +504,41 @@
mov ax,(si-4) ! Fetch mode ID
jmp _m_s

+
+check_vesa:
+ lea di,modelist+1024
+ sub bh,#VIDEO_FIRST_VESA>>8
+ mov cx,bx ! Get mode information structure
+ mov ax,#0x4f01
+ int 0x10
+ add bh,#VIDEO_FIRST_VESA>>8
+ cmp ax,#0x004f
+ jnz setbad
+
+ mov al,(di) ! Check capabilities.
+ and al,#0x19
+ cmp al,#0x09
+ jz setvesa ! this is a text mode
+
+ mov al,(di) ! Check capabilities.
+ and al,#0x99
+ cmp al,#0x99
+ jnz _setbad ! to bad, no linear frame buffer
+
+ sub bh,#VIDEO_FIRST_VESA>>8
+ or bx,#0x4000 ! want use linear frame buffer
+ mov ax,#0x4f02 ! VESA BIOS mode set call
+ int 0x10
+ cmp ax,#0x004f ! AL=4f if implemented, AH=0 if OK
+ jnz _setbad
+
+ movb [graphic_mode],#1 ! flag graphic mode
+ movb [do_restore],#0 ! no screen restore
+ stc
+ ret
+
+_setbad: br setbad ! Ugly...
+
!
! Recalculate vertical display end registers -- this fixes various
! inconsistencies of extended modes on many adapters. Called when
@@ -1797,6 +1884,7 @@
card_name: .word 0 ! Pointer to adapter name
scanning: .byte 0 ! Performing mode scan
do_restore: .byte 0 ! Screen contents altered during mode change
+graphic_mode: .byte 0 ! graphic mode with a linear frame buffer
svga_prefix: .byte VIDEO_FIRST_BIOS>>8 ! Default prefix for BIOS modes

!
diff -urN /data/vger-cvs/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- /data/vger-cvs/linux/arch/i386/kernel/setup.c Thu May 14 09:31:28 1998
+++ linux/arch/i386/kernel/setup.c Thu May 14 21:55:05 1998
@@ -221,7 +221,7 @@
request_region(0xf0,0x10,"fpu");

#if defined(CONFIG_ABSTRACT_CONSOLE) && defined(CONFIG_VT)
-#if defined(CONFIG_FB) && defined(CONFIG_FB_VGA)
+#if defined(CONFIG_FB) && (defined(CONFIG_FB_VGA) || defined(CONFIG_FB_VESA))
conswitchp = &fb_con;
#else
conswitchp = &vga_con;
diff -urN /data/vger-cvs/linux/drivers/char/fbmem.c linux/drivers/char/fbmem.c
--- /data/vger-cvs/linux/drivers/char/fbmem.c Sat Apr 18 09:35:28 1998
+++ linux/drivers/char/fbmem.c Sat May 16 10:13:39 1998
@@ -71,6 +71,7 @@
extern void s3triofb_setup(char *options, int *ints);
extern void vgafb_init(void);
extern void vgafb_setup(char *options, int *ints);
+extern void vesafb_init(void);



@@ -121,6 +122,9 @@
#ifdef CONFIG_FB_VGA
{ "vga", vgafb_init, vgafb_setup },
#endif
+#ifdef CONFIG_FB_VESA
+ { "vesa", vesafb_init, NULL },
+#endif
#ifdef CONFIG_GSP_RESOLVER
/* Not a real frame buffer device... */
{ "resolver", NULL, resolver_video_setup },
@@ -371,11 +375,17 @@
}
if ((vma->vm_end - vma->vm_start + vma->vm_offset) > len)
return -EINVAL;
+
+ if (info->phys_mem != NULL) {
+ start = info->phys_mem;
+ } else {
#ifdef __powerpc__
- start = iopa(start);
+ start = iopa(start);
#else
- start = __pa(start);
+ start = __pa(start);
#endif
+ }
+
vma->vm_offset += start;
if (vma->vm_offset & ~PAGE_MASK)
return -ENXIO;
diff -urN /data/vger-cvs/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- /data/vger-cvs/linux/drivers/video/Config.in Wed May 6 13:26:58 1998
+++ linux/drivers/video/Config.in Fri May 15 16:02:42 1998
@@ -52,6 +52,10 @@
if [ "$ARCH" = "i386" -o "$ARCH" = "alpha" -o "$ARCH" = "ppc" ]; then
bool 'VGA chipset support (text only)' CONFIG_FB_VGA
fi
+ if [ "$ARCH" = "i386" ]; then
+ bool 'VESA VGA graphics console' CONFIG_FB_VESA
+ define_bool CONFIG_VIDEO_SELECT y
+ fi
tristate 'Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL

bool 'Advanced low level driver options' CONFIG_FBCON_ADVANCED
@@ -99,12 +103,14 @@
"$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_OF" = "m" -o \
"$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_MAC" = "m" -o \
"$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_TGA" = "m" -o \
+ "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VESA" = "m" -o \
"$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
define_bool CONFIG_FBCON_CFB8 y
fi
if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATARI" = "m" -o \
"$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_ATY" = "m" -o \
"$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_MAC" = "m" -o \
+ "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VESA" = "m" -o \
"$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
define_bool CONFIG_FBCON_CFB16 y
fi
@@ -113,6 +119,7 @@
fi
if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATARI" = "m" -o \
"$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_ATY" = "m" -o \
+ "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VESA" = "m" -o \
"$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
define_bool CONFIG_FBCON_CFB32 y
fi
diff -urN /data/vger-cvs/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- /data/vger-cvs/linux/drivers/video/Makefile Thu May 14 09:40:31 1998
+++ linux/drivers/video/Makefile Thu May 14 10:30:22 1998
@@ -92,6 +92,10 @@
L_OBJS += vgafb.o
endif

+ifeq ($(CONFIG_FB_VESA),y)
+L_OBJS += vesafb.o
+endif
+
ifeq ($(CONFIG_FB_VIRGE),y)
L_OBJS += virgefb.o
else
diff -urN /data/vger-cvs/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- /data/vger-cvs/linux/drivers/video/vesafb.c Thu Jan 1 01:00:00 1970
+++ linux/drivers/video/vesafb.c Sat May 16 11:05:11 1998
@@ -0,0 +1,509 @@
+/*
+ * framebuffer driver for VBE 2.0 compilant graphic boards
+ *
+ * switching to graphics mode happens at boot time (while
+ * running in real mode, see arch/i386/video.S).
+ *
+ * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+
+#include <asm/io.h>
+
+#include "fbcon.h"
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb16.h"
+#include "fbcon-cfb32.h"
+
+#define dac_reg (0x3c8)
+#define dac_val (0x3c9)
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * card parameters
+ */
+
+/* card */
+char *video_base;
+int video_size;
+char *video_vbase; /* mapped */
+
+/* mode */
+int video_bpp;
+int video_width;
+int video_height;
+int video_type = FB_TYPE_PACKED_PIXELS;
+int video_visual;
+int video_linelength;
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo vesafb_defined = {
+ 0,0,0,0, /* W,H, W, H (virtual) load xres,xres_virtual*/
+ 0,0, /* virtual -> visible no offset */
+ 8, /* depth -> load bits_per_pixel */
+ 0, /* greyscale ? */
+ {0,0,0}, /* R */
+ {0,0,0}, /* G */
+ {0,0,0}, /* B */
+ {0,0,0}, /* transparency */
+ 0, /* standard pixel format */
+ FB_ACTIVATE_NOW,
+ -1,-1,
+ 0,
+ 0L,0L,0L,0L,0L,
+ 0L,0L,0, /* No sync info */
+ FB_VMODE_NONINTERLACED,
+ {0,0,0,0,0,0}
+};
+
+#define NUM_TOTAL_MODES 1
+#define NUM_PREDEF_MODES 1
+
+static struct display disp;
+static struct fb_info fb_info;
+static struct { u_char red, green, blue, pad; } palette[256];
+
+static int inverse = 0;
+
+struct vesafb_par
+{
+ void *unused;
+};
+
+static int currcon = 0;
+static int current_par_valid = 0;
+struct vesafb_par current_par;
+
+ /*
+ * Open/Release the frame buffer device
+ */
+
+static int vesafb_open(struct fb_info *info)
+{
+ /*
+ * Nothing, only a usage count for the moment
+ */
+ MOD_INC_USE_COUNT;
+ return(0);
+}
+
+static int vesafb_release(struct fb_info *info)
+{
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+static void vesafb_encode_var(struct fb_var_screeninfo *var,
+ struct vesafb_par *par)
+{
+ memcpy(var, &vesafb_defined, sizeof(struct fb_var_screeninfo));
+}
+
+static void vesafb_get_par(struct vesafb_par *par)
+{
+ *par=current_par;
+}
+
+static int fb_update_var(int con, struct fb_info *info)
+{
+ return 0;
+}
+
+static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
+{
+ struct vesafb_par par;
+
+ vesafb_get_par(&par);
+ vesafb_encode_var(var, &par);
+ return 0;
+}
+
+static void vesafb_encode_fix(struct fb_fix_screeninfo *fix,
+ struct vesafb_par *par)
+{
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ strcpy(fix->id,"VESA VGA");
+
+ fix->smem_start=(void*)video_vbase;
+ fix->smem_len=video_size;
+ fix->type = video_type;
+ fix->visual = video_visual;
+ fix->xpanstep=0;
+ fix->ypanstep=0;
+ fix->ywrapstep=0;
+ fix->line_length=video_linelength;
+ return;
+}
+
+static int vesafb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ struct vesafb_par par;
+ vesafb_get_par(&par);
+ vesafb_encode_fix(fix, &par);
+ return 0;
+}
+
+static int vesafb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ struct vesafb_par par;
+ if(con==-1)
+ {
+ vesafb_get_par(&par);
+ vesafb_encode_var(var, &par);
+ }
+ else
+ *var=fb_display[con].var;
+ return 0;
+}
+
+static void vesafb_set_disp(int con)
+{
+ struct fb_fix_screeninfo fix;
+ struct display *display;
+
+ if (con >= 0)
+ display = &fb_display[con];
+ else
+ display = &disp; /* used during initialization */
+
+ vesafb_get_fix(&fix, con, 0);
+
+ display->screen_base = (u_char *)(fix.smem_start);
+ display->visual = fix.visual;
+ display->type = fix.type;
+ display->type_aux = fix.type_aux;
+ display->ypanstep = fix.ypanstep;
+ display->ywrapstep = fix.ywrapstep;
+ display->line_length = fix.line_length;
+ display->next_line = fix.line_length;
+ display->can_soft_blank = 0;
+ display->inverse = inverse;
+
+ switch (video_bpp) {
+#ifdef CONFIG_FBCON_CFB8
+ case 8:
+ display->dispsw = &fbcon_cfb8;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB16
+ case 16:
+ display->dispsw = &fbcon_cfb16;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB32
+ case 32:
+ display->dispsw = &fbcon_cfb32;
+ break;
+#endif
+ default:
+ display->dispsw = NULL;
+ break;
+ }
+}
+
+static int vesafb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ int err;
+
+ if ((err=do_fb_set_var(var, 1)))
+ return err;
+ return 0;
+}
+
+static int vesa_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+ unsigned *blue, unsigned *transp,
+ const struct fb_info *fb_info)
+{
+ /*
+ * Read a single color register and split it into colors/transparent.
+ * Return != 0 for invalid regno.
+ */
+
+ if (video_bpp != 8 && regno >= 16)
+ return 1;
+ if (video_bpp == 8 && regno >= 256)
+ return 1;
+
+ *red = palette[regno].red;
+ *green = palette[regno].green;
+ *blue = palette[regno].blue;
+ return 0;
+}
+
+static int vesa_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ const struct fb_info *fb_info)
+{
+ /*
+ * Set a single color register. The values supplied are
+ * already rounded down to the hardware's capabilities
+ * (according to the entries in the `var' structure). Return
+ * != 0 for invalid regno.
+ */
+
+ if (video_bpp != 8 && regno >= 16)
+ return 1;
+ if (video_bpp == 8 && regno >= 256)
+ return 1;
+
+ palette[regno].red = red;
+ palette[regno].green = green;
+ palette[regno].blue = blue;
+
+ switch (video_bpp) {
+#ifdef CONFIG_FBCON_CFB8
+ case 8:
+ /* Hmm, can we do it _allways_ this way ??? */
+ outb_p(regno, dac_reg);
+ outb_p(red, dac_val);
+ outb_p(green, dac_val);
+ outb_p(blue, dac_val);
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB16
+ case 15:
+ case 16:
+ fbcon_cfb16_cmap[regno] =
+ (red << vesafb_defined.red.offset) | (green << 5) | blue;
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB24
+ case 24:
+ /* FIXME: todo */
+ break;
+#endif
+#ifdef CONFIG_FBCON_CFB32
+ case 32:
+ fbcon_cfb32_cmap[regno] =
+ (red << vesafb_defined.red.offset) |
+ (green << vesafb_defined.green.offset) |
+ (blue << vesafb_defined.blue.offset);
+ break;
+#endif
+ }
+ return 0;
+}
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+ if (con != currcon)
+ return;
+ if (fb_display[con].cmap.len)
+ fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1,
+ vesa_setcolreg, info);
+ else
+ fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
+ &fb_display[con].var, 1, vesa_setcolreg,
+ info);
+}
+
+static int vesafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ if (con == currcon) /* current console? */
+ return fb_get_cmap(cmap, &fb_display[con].var, kspc, vesa_getcolreg, info);
+ else if (fb_display[con].cmap.len) /* non default colormap? */
+ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+ else
+ fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel),
+ cmap, kspc ? 0 : 2);
+ return 0;
+}
+
+static int vesafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ int err;
+
+ if (!fb_display[con].cmap.len) { /* no colormap allocated? */
+ if ((err = fb_alloc_cmap(&fb_display[con].cmap,
+ 1<<fb_display[con].var.bits_per_pixel, 0)))
+ return err;
+ }
+ if (con == currcon) /* current console? */
+ return fb_set_cmap(cmap, &fb_display[con].var, kspc, vesa_setcolreg, info);
+ else
+ fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+ return 0;
+}
+
+static int vesafb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ /* no panning */
+ return -EINVAL;
+}
+
+static int vesafb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info)
+{
+ return -EINVAL;
+}
+
+static struct fb_ops vesafb_ops = {
+ vesafb_open,
+ vesafb_release,
+ vesafb_get_fix,
+ vesafb_get_var,
+ vesafb_set_var,
+ vesafb_get_cmap,
+ vesafb_set_cmap,
+ vesafb_pan_display,
+ vesafb_ioctl
+};
+
+void vesafb_setup(char *options, int *ints)
+{
+ char *this_opt;
+
+ fb_info.fontname[0] = '\0';
+
+ if (!options || !*options)
+ return;
+
+ for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+ if (!*this_opt) continue;
+
+ if (! strcmp(this_opt, "inverse"))
+ inverse=1;
+ else if (!strncmp(this_opt, "font:", 5)) {
+ strcpy(fb_info.fontname, this_opt+5);
+ printk("vesafb_setup: option %s\n", this_opt);
+ }
+ }
+}
+
+static int vesafb_switch(int con, struct fb_info *info)
+{
+ /* Do we have to save the colormap? */
+ if (fb_display[currcon].cmap.len)
+ fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1,
+ vesa_getcolreg, info);
+
+ currcon = con;
+ /* Install new colormap */
+ do_install_cmap(con, info);
+ fb_update_var(con, info);
+ return 0;
+
+#if 0
+ do_fb_set_var(&fb_display[con].var,1);
+ currcon=con;
+ return 0;
+#endif
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static void vesafb_blank(int blank, struct fb_info *info)
+{
+ /* Not supported */
+}
+
+__initfunc(void vesafb_init(void))
+{
+ int i,j;
+
+ if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB)
+ return;
+
+ video_base = (char*)screen_info.lfb_base;
+ video_size = screen_info.lfb_size;
+ video_bpp = screen_info.lfb_depth;
+ video_width = screen_info.lfb_width;
+ video_height = screen_info.lfb_height;
+ video_linelength = screen_info.lfb_linelength;
+ video_visual = (video_bpp == 8) ?
+ FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+ video_vbase = ioremap((unsigned long)video_base, video_size);
+
+ printk("vesafb: %dx%dx%d, linelength=%d\n",
+ video_width, video_height, video_bpp, video_linelength);
+ printk("vesafb: framebuffer at 0x%p, mapped to 0x%p, size %d\n",
+ video_base, video_vbase, video_size);
+
+ vesafb_defined.xres=video_width;
+ vesafb_defined.yres=video_height;
+ vesafb_defined.xres_virtual=video_width;
+ vesafb_defined.yres_virtual=video_height;
+ vesafb_defined.bits_per_pixel=video_bpp;
+
+ if (video_bpp > 8) {
+ vesafb_defined.red.offset = screen_info.red_pos;
+ vesafb_defined.red.length = screen_info.red_size;
+ vesafb_defined.green.offset = screen_info.green_pos;
+ vesafb_defined.green.length = screen_info.green_size;
+ vesafb_defined.blue.offset = screen_info.blue_pos;
+ vesafb_defined.blue.length = screen_info.blue_size;
+ vesafb_defined.transp.offset = screen_info.rsvd_pos;
+ vesafb_defined.transp.length = screen_info.rsvd_size;
+ printk("vesafb: directcolor: "
+ "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+ screen_info.rsvd_size,
+ screen_info.red_size,
+ screen_info.green_size,
+ screen_info.blue_size,
+ screen_info.rsvd_pos,
+ screen_info.red_pos,
+ screen_info.green_pos,
+ screen_info.blue_pos);
+ } else {
+ vesafb_defined.red.length = 6;
+ vesafb_defined.green.length = 6;
+ vesafb_defined.blue.length = 6;
+ 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];
+ }
+ }
+ request_region(0x3c0, 32, "vga+");
+
+ strcpy(fb_info.modename, "VESA VGA");
+ fb_info.phys_mem = video_base;
+ fb_info.changevar = NULL;
+ fb_info.node = -1;
+ fb_info.fbops = &vesafb_ops;
+ fb_info.disp=&disp;
+ fb_info.switch_con=&vesafb_switch;
+ fb_info.updatevar=&fb_update_var;
+ fb_info.blank=&vesafb_blank;
+ do_fb_set_var(&vesafb_defined,1);
+
+ if (register_framebuffer(&fb_info)<0)
+ return;
+
+ vesafb_get_var(&disp.var, -1, &fb_info);
+ vesafb_set_disp(-1);
+
+ printk("fb%d: %s frame buffer device\n",
+ GET_FB_IDX(fb_info.node), fb_info.modename);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -urN /data/vger-cvs/linux/drivers/video/vgafb.c linux/drivers/video/vgafb.c
--- /data/vger-cvs/linux/drivers/video/vgafb.c Wed Apr 29 16:54:36 1998
+++ linux/drivers/video/vgafb.c Fri May 15 00:32:53 1998
@@ -415,6 +415,9 @@
u16 saved;
u16 *p;

+ if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB)
+ return;
+
vga_video_num_lines = ORIG_VIDEO_LINES;
vga_video_num_columns = ORIG_VIDEO_COLS;

diff -urN /data/vger-cvs/linux/include/linux/fb.h linux/include/linux/fb.h
--- /data/vger-cvs/linux/include/linux/fb.h Thu May 14 09:43:47 1998
+++ linux/include/linux/fb.h Sat May 16 10:07:59 1998
@@ -261,6 +261,7 @@
struct fb_info {
char modename[40]; /* default video mode */
int node;
+ unsigned long phys_mem; /* physical fb memory address */
struct fb_ops *fbops;
struct fb_monspecs monspecs;
struct display *disp; /* initial display variable */
diff -urN /data/vger-cvs/linux/include/linux/tty.h linux/include/linux/tty.h
--- /data/vger-cvs/linux/include/linux/tty.h Sat Apr 18 09:37:55 1998
+++ linux/include/linux/tty.h Fri May 15 16:34:45 1998
@@ -52,6 +52,22 @@
unsigned char orig_video_lines;
unsigned char orig_video_isVGA;
unsigned short orig_video_points;
+
+ /* VESA graphic mode -- linear frame buffer */
+ unsigned short lfb_width;
+ unsigned short lfb_height;
+ unsigned short lfb_depth;
+ unsigned long lfb_base;
+ unsigned long lfb_size;
+ unsigned short lfb_linelength;
+ unsigned char red_size;
+ unsigned char red_pos;
+ unsigned char green_size;
+ unsigned char green_pos;
+ unsigned char blue_size;
+ unsigned char blue_pos;
+ unsigned char rsvd_size;
+ unsigned char rsvd_pos;
};

extern struct screen_info screen_info;
@@ -70,6 +86,7 @@
#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */
#define VIDEO_TYPE_EGAC 0x21 /* EGA in Color Mode */
#define VIDEO_TYPE_VGAC 0x22 /* VGA+ in Color Mode */
+#define VIDEO_TYPE_VLFB 0x23 /* VESA VGA in graphic mode */

#define VIDEO_TYPE_TGAC 0x40 /* DEC TGA */

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu