patch-2.1.124 linux/drivers/video/vesafb.c
Next file: linux/drivers/video/vfb.c
Previous file: linux/drivers/video/valkyriefb.h
Back to the patch index
Back to the overall index
- Lines: 442
- Date:
Sun Oct 4 10:00:26 1998
- Orig file:
v2.1.123/linux/drivers/video/vesafb.c
- Orig date:
Mon Aug 3 12:45:47 1998
diff -u --recursive --new-file v2.1.123/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c
@@ -4,9 +4,9 @@
* 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>
+ * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
*
- */
+ */
#include <linux/module.h>
#include <linux/kernel.h>
@@ -21,13 +21,16 @@
#include <linux/selection.h>
#include <linux/ioport.h>
#include <linux/init.h>
+#include <linux/config.h>
#include <asm/io.h>
+#include <asm/mtrr.h>
-#include "fbcon.h"
-#include "fbcon-cfb8.h"
-#include "fbcon-cfb16.h"
-#include "fbcon-cfb32.h"
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
#define dac_reg (0x3c8)
#define dac_val (0x3c9)
@@ -75,19 +78,29 @@
static struct display disp;
static struct fb_info fb_info;
-static struct { u_char red, green, blue, pad; } palette[256];
-
-static int inverse = 0;
+static struct { u_short blue, green, red, pad; } palette[256];
+static union {
+#ifdef FBCON_HAS_CFB16
+ u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB24
+ u32 cfb24[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+ u32 cfb32[16];
+#endif
+} fbcon_cmap;
-static int currcon = 0;
+static int inverse = 0;
+static int currcon = 0;
-/* --------------------------------------------------------------------- */
-/* speed up scrolling */
+static int pmi_setpal = 0; /* pmi for palette changes ??? */
+static int ypan = 0;
+static int ywrap = 0;
+static unsigned short *pmi_base = 0;
+static void (*pmi_start)(void);
+static void (*pmi_pal)(void);
-#define USE_REDRAW 1
-#define USE_MEMMOVE 2
-
-static int vesafb_scroll = USE_REDRAW;
static struct display_switch vesafb_sw;
/* --------------------------------------------------------------------- */
@@ -111,8 +124,37 @@
return(0);
}
-static int fb_update_var(int con, struct fb_info *info)
+static int vesafb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
{
+ int offset;
+
+ if (var->xoffset)
+ return -EINVAL;
+ if (ypan && var->yoffset+var->yres > var->yres_virtual)
+ return -EINVAL;
+ if (ywrap && var->yoffset > var->yres_virtual)
+ return -EINVAL;
+
+ offset = (var->yoffset * video_linelength + var->xoffset) / 4;
+
+ __asm__ __volatile__(
+ "call *(%%edi)"
+ : /* no return value */
+ : "a" (0x4f07), /* EAX */
+ "b" (0), /* EBX */
+ "c" (offset), /* ECX */
+ "d" (offset >> 16), /* EDX */
+ "D" (&pmi_start)); /* EDI */
+ return 0;
+}
+
+static int vesafb_update_var(int con, struct fb_info *info)
+{
+ if (con == currcon && (ywrap || ypan)) {
+ struct fb_var_screeninfo *var = &fb_display[currcon].var;
+ return vesafb_pan_display(var,con,info);
+ }
return 0;
}
@@ -126,9 +168,9 @@
fix->smem_len=video_size;
fix->type = video_type;
fix->visual = video_visual;
- fix->xpanstep=0;
- fix->ypanstep=0;
- fix->ywrapstep=0;
+ fix->xpanstep = 0;
+ fix->ypanstep = (ywrap || ypan) ? 1 : 0;
+ fix->ywrapstep = ywrap ? 1 : 0;
fix->line_length=video_linelength;
return 0;
}
@@ -179,19 +221,28 @@
case 15:
case 16:
sw = &fbcon_cfb16;
+ display->dispsw_data = fbcon_cmap.cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ sw = &fbcon_cfb24;
+ display->dispsw_data = fbcon_cmap.cfb24;
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
sw = &fbcon_cfb32;
+ display->dispsw_data = fbcon_cmap.cfb32;
break;
#endif
default:
+ sw = &fbcon_dummy;
return;
}
memcpy(&vesafb_sw, sw, sizeof(*sw));
display->dispsw = &vesafb_sw;
- if (vesafb_scroll == USE_REDRAW) {
+ if (!ypan && !ywrap) {
display->scrollmode = SCROLL_YREDRAW;
vesafb_sw.bmove = fbcon_redraw_bmove;
}
@@ -219,9 +270,41 @@
*red = palette[regno].red;
*green = palette[regno].green;
*blue = palette[regno].blue;
+ *transp = 0;
return 0;
}
+#ifdef FBCON_HAS_CFB8
+
+static void vesa_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
+{
+ struct { u_char blue, green, red, pad; } entry;
+
+ if (pmi_setpal) {
+ entry.red = red >> 10;
+ entry.green = green >> 10;
+ entry.blue = blue >> 10;
+ entry.pad = 0;
+ __asm__ __volatile__(
+ "call *(%%esi)"
+ : /* no return value */
+ : "a" (0x4f09), /* EAX */
+ "b" (0), /* EBX */
+ "c" (1), /* ECX */
+ "d" (regno), /* EDX */
+ "D" (&entry), /* EDI */
+ "S" (&pmi_pal)); /* ESI */
+ } else {
+ /* without protected mode interface, try VGA registers... */
+ outb_p(regno, dac_reg);
+ outb_p(red >> 10, dac_val);
+ outb_p(green >> 10, dac_val);
+ outb_p(blue >> 10, dac_val);
+ }
+}
+
+#endif
+
static int vesa_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *fb_info)
@@ -235,7 +318,7 @@
if (regno >= video_cmap_len)
return 1;
-
+
palette[regno].red = red;
palette[regno].green = green;
palette[regno].blue = blue;
@@ -243,28 +326,44 @@
switch (video_bpp) {
#ifdef FBCON_HAS_CFB8
case 8:
- /* Hmm, can we do it _always_ this way ??? */
- outb_p(regno, dac_reg);
- outb_p(red, dac_val);
- outb_p(green, dac_val);
- outb_p(blue, dac_val);
+ vesa_setpalette(regno,red,green,blue);
break;
#endif
#ifdef FBCON_HAS_CFB16
case 15:
case 16:
- fbcon_cfb16_cmap[regno] =
- (red << vesafb_defined.red.offset) | (green << 5) | blue;
+ if (vesafb_defined.red.offset == 10) {
+ /* 1:5:5:5 */
+ fbcon_cmap.cfb16[regno] =
+ ((red & 0xf800) >> 1) |
+ ((green & 0xf800) >> 6) |
+ ((blue & 0xf800) >> 11);
+ } else {
+ /* 0:5:6:5 */
+ fbcon_cmap.cfb16[regno] =
+ ((red & 0xf800) ) |
+ ((green & 0xfc00) >> 5) |
+ ((blue & 0xf800) >> 11);
+ }
break;
#endif
#ifdef FBCON_HAS_CFB24
case 24:
- /* FIXME: todo */
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ fbcon_cmap.cfb24[regno] =
+ (red << vesafb_defined.red.offset) |
+ (green << vesafb_defined.green.offset) |
+ (blue << vesafb_defined.blue.offset);
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
- fbcon_cfb32_cmap[regno] =
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ fbcon_cmap.cfb32[regno] =
(red << vesafb_defined.red.offset) |
(green << vesafb_defined.green.offset) |
(blue << vesafb_defined.blue.offset);
@@ -279,11 +378,9 @@
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);
+ fb_set_cmap(&fb_display[con].cmap, 1, vesa_setcolreg, info);
else
- fb_set_cmap(fb_default_cmap(video_cmap_len),
- &fb_display[con].var, 1, vesa_setcolreg,
+ fb_set_cmap(fb_default_cmap(video_cmap_len), 1, vesa_setcolreg,
info);
}
@@ -291,7 +388,7 @@
struct fb_info *info)
{
if (con == currcon) /* current console? */
- return fb_get_cmap(cmap, &fb_display[con].var, kspc, vesa_getcolreg, info);
+ return fb_get_cmap(cmap, 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
@@ -311,20 +408,13 @@
return err;
}
if (con == currcon) /* current console? */
- return fb_set_cmap(cmap, &fb_display[con].var, kspc, vesa_setcolreg, info);
+ return fb_set_cmap(cmap, 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,
+static int vesafb_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg, int con,
struct fb_info *info)
{
@@ -355,14 +445,18 @@
for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
if (!*this_opt) continue;
- printk("vesafb_setup: option %s\n", this_opt);
-
if (! strcmp(this_opt, "inverse"))
inverse=1;
else if (! strcmp(this_opt, "redraw"))
- vesafb_scroll = USE_REDRAW;
- else if (! strcmp(this_opt, "memmove"))
- vesafb_scroll = USE_MEMMOVE;
+ ywrap=0,ypan=0;
+ else if (! strcmp(this_opt, "ypan"))
+ ywrap=0,ypan=1;
+ else if (! strcmp(this_opt, "ywrap"))
+ ywrap=1,ypan=0;
+ else if (! strcmp(this_opt, "vgapal"))
+ pmi_setpal=0;
+ else if (! strcmp(this_opt, "pmipal"))
+ pmi_setpal=1;
else if (!strncmp(this_opt, "font:", 5))
strcpy(fb_info.fontname, this_opt+5);
}
@@ -372,13 +466,14 @@
{
/* 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);
+ fb_get_cmap(&fb_display[currcon].cmap, 1, vesa_getcolreg,
+ info);
currcon = con;
/* Install new colormap */
do_install_cmap(con, info);
- return 0;
+ vesafb_update_var(con,info);
+ return 1;
}
/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
@@ -400,24 +495,62 @@
video_width = screen_info.lfb_width;
video_height = screen_info.lfb_height;
video_linelength = screen_info.lfb_linelength;
- video_size = video_linelength * video_height /* screen_info.lfb_size */;
+ video_size = screen_info.lfb_size * 65536;
video_visual = (video_bpp == 8) ?
- FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+ FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
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);
- if (vesafb_scroll == USE_REDRAW) printk("vesafb: scrolling=redraw\n");
- if (vesafb_scroll == USE_MEMMOVE) printk("vesafb: scrolling=memmove\n");
-
+ printk("vesafb: framebuffer at 0x%p, mapped to 0x%p, size %dk\n",
+ video_base, video_vbase, video_size/1024);
+ printk("vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
+ video_width, video_height, video_bpp, video_linelength, screen_info.pages);
+
+ if (screen_info.vesapm_seg) {
+ printk("vesafb: protected mode interface info at %04x:%04x\n",
+ screen_info.vesapm_seg,screen_info.vesapm_off);
+ }
+
+ if (screen_info.vesapm_seg < 0xc000)
+ ywrap = ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */
+
+ if (ypan || ywrap || pmi_setpal) {
+ pmi_base = (unsigned short*)(__PAGE_OFFSET+((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
+ pmi_start = (void*)((char*)pmi_base + pmi_base[1]);
+ pmi_pal = (void*)((char*)pmi_base + pmi_base[2]);
+ printk("vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal);
+ if (pmi_base[3]) {
+ printk("vesafb: pmi: ports = ");
+ for (i = pmi_base[3]/2; pmi_base[i] != 0xffff; i++)
+ printk("%x ",pmi_base[i]);
+ printk("\n");
+ if (pmi_base[i] != 0xffff) {
+ /*
+ * memory areas not supported (yet?)
+ *
+ * Rules are: we have to set up a descriptor for the requested
+ * memory area and pass it in the ES register to the BIOS function.
+ */
+ printk("vesafb: can't handle memory requests, pmi disabled\n");
+ ywrap = ypan = pmi_setpal = 0;
+ }
+ }
+ }
+
vesafb_defined.xres=video_width;
vesafb_defined.yres=video_height;
vesafb_defined.xres_virtual=video_width;
- vesafb_defined.yres_virtual=video_height;
+ vesafb_defined.yres_virtual=video_size / video_linelength;
vesafb_defined.bits_per_pixel=video_bpp;
+ if ((ypan || ywrap) && vesafb_defined.yres_virtual > video_height) {
+ printk("vesafb: scrolling: %s using protected mode interface, yres_virtual=%d\n",
+ ywrap ? "ywrap" : "ypan",vesafb_defined.yres_virtual);
+ } else {
+ printk("vesafb: scrolling: redraw\n");
+ vesafb_defined.yres_virtual = video_height;
+ ypan = ywrap = 0;
+ }
+
if (video_bpp > 8) {
vesafb_defined.red.offset = screen_info.red_pos;
vesafb_defined.red.length = screen_info.red_size;
@@ -451,6 +584,9 @@
video_cmap_len = 256;
}
request_region(0x3c0, 32, "vga+");
+#ifdef CONFIG_MTRR
+ mtrr_add((unsigned long)video_base, video_size, MTRR_TYPE_WRCOMB, 1);
+#endif
strcpy(fb_info.modename, "VESA VGA");
fb_info.changevar = NULL;
@@ -458,8 +594,9 @@
fb_info.fbops = &vesafb_ops;
fb_info.disp=&disp;
fb_info.switch_con=&vesafb_switch;
- fb_info.updatevar=&fb_update_var;
+ fb_info.updatevar=&vesafb_update_var;
fb_info.blank=&vesafb_blank;
+ fb_info.flags=FBINFO_FLAG_DEFAULT;
vesafb_set_disp(-1);
if (register_framebuffer(&fb_info)<0)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov