[patch] graphic console / framebuffer on intel

Gerd Knorr (kraxel@goldbach.isdn.cs.tu-berlin.de)
Thu, 14 May 1998 16:55:55 +0200 (MEST)


Hi !

Running linux console in 1024x768 here. Patch against vger's CVS tree
below. Not very comfortable yet, I just checked if it is possible...

Here is how it is done:

1) It switches the vga board into graphics mode at boot time, with the
help of the VESA BIOS extentions. That's currently done using the
GFX_HACK thing in video.S. VIDEO_GFX_BIOS_BX holds the VESA video mode
number (hard coded for now) with the 14th bit set (this instructs the
BIOS to turn on the linear frame buffer -- requires VBE 2.0).

2) A new, simple frame-buffer driver which simply maps the linear frame
buffer and registers as frame buffer device. The video mode parameters
are hard coded too (in vesafb.c).

To use this, you have to enable CONFIG_VIDEO_SELECT and CONFIG_FB_VESA,
disable CONFIG_FB_VGA, fill in the framebuffer parameters in vesafb.c,
recompile and boot your box with "vga=3848" (3848 == 0x0f08).

Still missing:

* no sanity checks
* no runtime configuration
* scrolling is painful slow
* get/set colormap not implemented
* works for 8bit only

Cool stuff:

* There is a graphic penguin logo at boot time!
Well, colors are wrong becauce there is no colormap support yet, but
you can see it is a penguin...
* It provides a nice large screen (128 cols + 48 lines with 1024x768)
without using tiny, unreadable fonts.
* Framebuffer device for intel boxes

Gerd

--------------------- cut here ------------------------
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 Thu May 14 15:20:21 1998
@@ -30,9 +30,9 @@
! A special hack allowing to force specific BIOS mode ID along with specific
! dimensions. Especially useful for certain X-Window graphics mode hacks
! (e.g., 800x600 modes on IBM ThinkPad).
-#undef CONFIG_VIDEO_GFX_HACK
+#define CONFIG_VIDEO_GFX_HACK
#define VIDEO_GFX_BIOS_AX 0x4f02 /* 800x600 on ThinkPad */
-#define VIDEO_GFX_BIOS_BX 0x0102
+#define VIDEO_GFX_BIOS_BX 0x4105
#define VIDEO_GFX_DUMMY_RESOLUTION 0x6425 /* 100x37 */

! This code uses an extended set of video mode numbers. These include:
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 13:33:49 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 Thu May 14 10:35:26 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);



@@ -120,6 +121,9 @@
#endif
#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... */
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 Thu May 14 10:32:09 1998
@@ -51,6 +51,7 @@
fi
if [ "$ARCH" = "i386" -o "$ARCH" = "alpha" -o "$ARCH" = "ppc" ]; then
bool 'VGA chipset support (text only)' CONFIG_FB_VGA
+ bool 'VESA VGA graphics console' CONFIG_FB_VESA
fi
tristate 'Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL

@@ -99,12 +100,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 +116,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 Thu May 14 15:24:48 1998
@@ -0,0 +1,354 @@
+#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 <asm/io.h>
+
+#include "fbcon.h"
+#include "fbcon-cfb8.h"
+#include "fbcon-cfb16.h"
+#include "fbcon-cfb32.h"
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * card parameters -- hard coded for now...
+ */
+
+/* card */
+char *video_base = (char*)0xff000000;
+int video_size = 4*1024*1024;
+char *video_vbase; /* mapped */
+
+/* mode */
+int video_bpp = 8;
+int video_width = 1024;
+int video_height = 768;
+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 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)
+{
+ memset(var, 0, sizeof(struct fb_var_screeninfo));
+ var->xres=video_width;
+ var->yres=video_height;
+ var->xres_virtual=video_width;
+ var->yres_virtual=video_height;
+ var->xoffset=0;
+ var->yoffset=0;
+ var->bits_per_pixel = video_bpp;
+ var->grayscale=0;
+ var->transp.offset=0;
+ var->transp.length=0;
+ var->transp.msb_right=0;
+ var->nonstd=0;
+ var->activate=0;
+ var->height= -1;
+ var->width= -1;
+ var->vmode=FB_VMODE_NONINTERLACED;
+ var->pixclock=0;
+ var->sync=0;
+ var->left_margin=0;
+ var->right_margin=0;
+ var->upper_margin=0;
+ var->lower_margin=0;
+ var->hsync_len=0;
+ var->vsync_len=0;
+ return;
+}
+
+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;
+}
+
+extern int console_loglevel;
+
+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 vesafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ return 0;
+}
+
+static int vesafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ 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_fb_set_var(&fb_display[con].var,1);
+ currcon=con;
+ return 0;
+}
+
+/* 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))
+{
+ /* TODO: get video mode information */
+
+ video_linelength = video_width * ((video_bpp+7)/8);
+ 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, addr 0x%p, mapped to 0x%p, size %d\n",
+ video_width, video_height, video_bpp,
+ 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;
+
+ strcpy(fb_info.modename, "VESA VGA");
+ 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);
+}
+

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