diff options
author | Keith Packard <keithp@keithp.com> | 2000-09-03 05:11:46 +0000 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2000-09-03 05:11:46 +0000 |
commit | c97fb611dd7dedef6d075ef9d56f3d32c8018d39 (patch) | |
tree | 92dbb45f2e31b7ab709255d2d07a606f466c1a38 /hw/kdrive/vesa | |
parent | 38059656849a5bab5b56b23359a90aca4ba396c7 (diff) |
Rework vesa driver for shadowing and multiple screen support. Allow enable
to fail and avoid crashing
Diffstat (limited to 'hw/kdrive/vesa')
-rw-r--r-- | hw/kdrive/vesa/Imakefile | 8 | ||||
-rw-r--r-- | hw/kdrive/vesa/Xvesa.man | 33 | ||||
-rw-r--r-- | hw/kdrive/vesa/vbe.c | 276 | ||||
-rw-r--r-- | hw/kdrive/vesa/vbe.h | 18 | ||||
-rw-r--r-- | hw/kdrive/vesa/vesa.c | 545 | ||||
-rw-r--r-- | hw/kdrive/vesa/vesa.h | 32 |
6 files changed, 768 insertions, 144 deletions
diff --git a/hw/kdrive/vesa/Imakefile b/hw/kdrive/vesa/Imakefile index bcf8613cb..b891e70b3 100644 --- a/hw/kdrive/vesa/Imakefile +++ b/hw/kdrive/vesa/Imakefile @@ -1,14 +1,12 @@ XCOMM $XFree86$ - -#include <Server.tmpl> +KDRIVE=.. +#include "../Kdrive.tmpl" SRCS = vesa.c vesainit.c vbe.c OBJS = vesa.o vesainit.o vbe.o -INCLUDES = -I.. -I. -I$(XBUILDINCDIR) -I$(FONTINCSRC) \ - -I../../../fb -I../../../mi -I../../../include -I../../../os \ - -I$(EXTINCSRC) -I$(XINCLUDESRC) +INCLUDES = -I. $(KDINCS) NormalLibraryObjectRule() NormalLibraryTarget(vesa,$(OBJS)) diff --git a/hw/kdrive/vesa/Xvesa.man b/hw/kdrive/vesa/Xvesa.man index eafd3539b..958934aa9 100644 --- a/hw/kdrive/vesa/Xvesa.man +++ b/hw/kdrive/vesa/Xvesa.man @@ -7,8 +7,12 @@ Xvesa \- VESA VBE tiny X server .RI [ :display ] .RI [ option ...] .SH DESCRIPTION -Xvesa is an X server for Linux on the x86 platform. Xvesa manipulates -the video hardware by running the VESA BIOS in VM86 mode. It +.B Xvesa +is a generic X server for Linux on the x86 platform. +.B Xvesa +doesn't know about any particular hardware, and sets the video mode by +running the video BIOS in VM86 mode. +.B Xvesa therefore runs untrusted code with full priviledges, and is one of the most insecure X servers available. .B Run at your own risk. @@ -23,11 +27,10 @@ specifies the VESA video mode to use. If mode .I n is not supported by your BIOS and hardware, .B Xvesa -will fail, hang your system, or make your monitor explode. You are on -your own. The list of video modes that your BIOS claims to support -can be obtained by using the -.B -listmodes -option. +will fail, hang your system, or make your monitor explode; you are on +your own. This option is ignored if the +.B -screen +option was used. .TP 8 .B -listmodes tells the server to list all supported video modes. If @@ -40,8 +43,20 @@ the server won't be able to use. .TP 8 .B -force -tells the server to disable some sanity checks and use the specified -mode even if the BIOS claims not to support it. +disables some sanity checks and use the specified mode even if the +BIOS claims not to support it. +.TP 8 +.B -shadow +use a shadow framebuffer even if it is not strictly necessary. This +may dramatically improve performance on some machines. +.TP 8 +.B -nolinear +don't use a linear framebuffer even if one is available. You don't +want to use this option. +.TP 8 +.B -swaprgb +pass RGB values in the order that works on my machine. Use this if +the colours are wrong in PseudoColor modes. .SH KEYBOARD Xvesa handles the keyboard in the same manner as the .B Xfbdev diff --git a/hw/kdrive/vesa/vbe.c b/hw/kdrive/vesa/vbe.c index 98e51560d..1e709b9de 100644 --- a/hw/kdrive/vesa/vbe.c +++ b/hw/kdrive/vesa/vbe.c @@ -114,7 +114,8 @@ VbeSetup() MAP_SHARED | MAP_FIXED, devmem, HIMEM_BASE); if(hiMem == MAP_FAILED) { - munmap(magicMem, MAGICMEM_SIZE); + ErrorF("Couldn't map high memory\n"); + munmap(magicMem, MAGICMEM_SIZE); munmap(loMem, LOMEM_SIZE); goto fail; } @@ -128,7 +129,6 @@ VbeSetup() vi->magicMem = magicMem; vi->loMem = loMem; vi->hiMem = hiMem; - vi->fb = NULL; vi->brk = LOMEM_BASE; stack_base = VbeAllocateMemory(vi, STACK_SIZE); @@ -152,7 +152,10 @@ VbeSetup() vi->palette_scratch_base = ~0; vi->palette_format = 6; vi->palette_wait = 0; - + vi->windowA_offset = vi->windowB_offset = -1; + vi->last_window = 1; + vi->vga_palette = 1; + memset(&vi->vms, 0, sizeof(struct vm86_struct)); vi->vms.flags = 0; vi->vms.screen_bitmap = 0; @@ -181,8 +184,6 @@ VbeSetup() void VbeCleanup(VbeInfoPtr vi) { - if(vi->fb) - VbeUnmapFramebuffer(vi); munmap(vi->magicMem, MAGICMEM_SIZE); munmap(vi->loMem, LOMEM_SIZE); munmap(vi->hiMem, HIMEM_SIZE); @@ -233,12 +234,17 @@ VbeGetModeInfo(VbeInfoPtr vi, int mode) } int -VbeSetMode(VbeInfoPtr vi, int mode) +VbeSetMode(VbeInfoPtr vi, int mode, int linear) { int code; + vi->windowA_offset = vi->windowB_offset = -1; + vi->last_window = 1; + vi->vms.regs.eax = 0x4F02; - vi->vms.regs.ebx = (mode & 0xFFFF) | 0xC000; + vi->vms.regs.ebx = (mode & 0xFFFF) | 0x8000; + if(linear) + vi->vms.regs.ebx |= 0x4000; code = VbeDoInterrupt10(vi); if(code < 0) return -1; @@ -306,11 +312,24 @@ VbeRestoreState(VbeInfoPtr vi) return 0; } +int +VbeSetTextMode(VbeInfoPtr vi, int mode) +{ + int code; + + vi->vms.regs.eax = mode & 0x7f; + code = VbeDoInterrupt10(vi); + if(code < 0) + return -1; + return 0; +} + void * -VbeMapFramebuffer(VbeInfoPtr vi) { +VbeMapFramebuffer(VbeInfoPtr vi, + VbeModeInfoBlock *vmib) +{ U8 *fb; VbeInfoBlock *vib = (VbeInfoBlock*)&(LM(vi, vi->vib_base)); - VbeModeInfoBlock *vmib = (VbeModeInfoBlock*)&(LM(vi, vi->vmib_base)); int size; int pagesize = getpagesize(), before, after; @@ -329,18 +348,28 @@ VbeMapFramebuffer(VbeInfoPtr vi) { return NULL; } - vi->fb = fb; - vi->fb_size = before + size + after; return fb + before; } int -VbeUnmapFramebuffer(VbeInfoPtr vi) +VbeUnmapFramebuffer(VbeInfoPtr vi, + VbeModeInfoBlock *vmib, + void *fb) { int code; - if(!vi->fb) - ErrorF("Unmapping frambuffer not mapped\n"); - code = munmap(vi->fb, vi->fb_size); + VbeInfoBlock *vib = (VbeInfoBlock*)&(LM(vi, vi->vib_base)); + int size; + int pagesize = getpagesize(), before, after; + + size = 1024 * 64L * vib->TotalMemory; + + before = vmib->PhysBasePtr % pagesize; + after = pagesize - ((vmib->PhysBasePtr + size) % pagesize); + if(after == pagesize) + after = 0; + + fb = (void *) ((char *) fb - before); + code = munmap(fb, before + size + after); if(code) { ErrorF("Couldn't unmap framebuffer: %d\n", errno); return -1; @@ -375,7 +404,7 @@ int VbeSetPalette(VbeInfoPtr vi, int first, int number, U8 *entries) { U8 *palette_scratch; - int i, code; + int i, j, code; if(number == 0) return 0; @@ -395,21 +424,41 @@ VbeSetPalette(VbeInfoPtr vi, int first, int number, U8 *entries) return -1; } - for(i=0; i<number*4; i++) - palette_scratch[i] = entries[i] >> (8 - vi->palette_format); - - vi->vms.regs.eax = 0x4F09; - if(vi->palette_wait) - vi->vms.regs.ebx = 0x80; + if (vi->vga_palette) + { + vi->vms.regs.eax = 0x1012; + vi->vms.regs.ebx = first; + vi->vms.regs.ecx = number; + vi->vms.regs.es = POINTER_SEGMENT(vi->palette_scratch_base); + vi->vms.regs.edx = POINTER_OFFSET(vi->palette_scratch_base); + j = 0; + i = 0; + while (number--) + { + palette_scratch[j++] = entries[i++] >> (8-vi->palette_format); + palette_scratch[j++] = entries[i++] >> (8-vi->palette_format); + palette_scratch[j++] = entries[i++] >> (8-vi->palette_format); + i++; + } + } else - vi->vms.regs.ebx = 0x00; - vi->vms.regs.ecx = number; - vi->vms.regs.edx = first; - vi->vms.regs.es = POINTER_SEGMENT(vi->palette_scratch_base); - vi->vms.regs.edi = POINTER_OFFSET(vi->palette_scratch_base); + { + for(i=0; i<number*4; i++) + palette_scratch[i] = entries[i] >> (8 - vi->palette_format); + + vi->vms.regs.eax = 0x4F09; + if(vi->palette_wait) + vi->vms.regs.ebx = 0x80; + else + vi->vms.regs.ebx = 0x00; + vi->vms.regs.ecx = number; + vi->vms.regs.edx = first; + vi->vms.regs.es = POINTER_SEGMENT(vi->palette_scratch_base); + vi->vms.regs.edi = POINTER_OFFSET(vi->palette_scratch_base); + } code = VbeDoInterrupt10(vi); if(code < 0) - return -1; + return -1; return 0; } @@ -417,7 +466,7 @@ int VbeGetPalette(VbeInfoPtr vi, int first, int number, U8 *entries) { U8 *palette_scratch; - int i, code; + int i, j, code; code = PreparePalette(vi); if(code < 0) @@ -434,18 +483,45 @@ VbeGetPalette(VbeInfoPtr vi, int first, int number, U8 *entries) return -1; } - vi->vms.regs.eax = 0x4F09; - vi->vms.regs.ebx = 0x01; - vi->vms.regs.ecx = number; - vi->vms.regs.edx = first; - vi->vms.regs.es = POINTER_SEGMENT(vi->palette_scratch_base); - vi->vms.regs.edi = POINTER_OFFSET(vi->palette_scratch_base); - code = VbeDoInterrupt10(vi); - if(code < 0) - return -1; - - for(i=0; i<number*4; i++) - entries[i] = palette_scratch[i] << (8-vi->palette_format); +retry: + if (vi->vga_palette) + { + vi->vms.regs.eax = 0x1017; + vi->vms.regs.ebx = first; + vi->vms.regs.ecx = number; + vi->vms.regs.es = POINTER_SEGMENT(vi->palette_scratch_base); + vi->vms.regs.edx = POINTER_OFFSET(vi->palette_scratch_base); + code = VbeDoInterrupt10(vi); + if(code < 0) + return -1; + j = 0; + i = 0; + while (number--) + { + entries[i++] = palette_scratch[j++] << (8-vi->palette_format); + entries[i++] = palette_scratch[j++] << (8-vi->palette_format); + entries[i++] = palette_scratch[j++] << (8-vi->palette_format); + entries[i++] = 0; + } + } + else + { + vi->vms.regs.eax = 0x4F09; + vi->vms.regs.ebx = 0x01; + vi->vms.regs.ecx = number; + vi->vms.regs.edx = first; + vi->vms.regs.es = POINTER_SEGMENT(vi->palette_scratch_base); + vi->vms.regs.edi = POINTER_OFFSET(vi->palette_scratch_base); + code = VbeDoInterrupt10(vi); + if(code < 0) + { + vi->vga_palette = TRUE; + goto retry; + } + + for(i=0; i<number*4; i++) + entries[i] = palette_scratch[i] << (8-vi->palette_format); + } return 0; } @@ -458,7 +534,6 @@ VbeSetPaletteOptions(VbeInfoPtr vi, U8 bits, int wait) ErrorF("Impossible palette format %d\n", vi->palette_format); return -1; } - ErrorF("Setting palette format to %d\n", vi->palette_format); if(bits != vi->palette_format) { vi->palette_format = 0; vi->vms.regs.eax = 0x4F08; @@ -472,6 +547,94 @@ VbeSetPaletteOptions(VbeInfoPtr vi, U8 bits, int wait) return 0; } +static int +VbeReallySetWindow(VbeInfoPtr vi, U8 window, U16 winnum) +{ + int code; + vi->vms.regs.eax = 0x4F05; + vi->vms.regs.ebx = window; + vi->vms.regs.edx = winnum; + code = VbeDoInterrupt10(vi); + if(code < 0) + return -1; + return 0; +} + +void * +VbeSetWindow(VbeInfoPtr vi, int offset, int purpose, int *size_return) +{ + VbeModeInfoBlock *vmib = (VbeModeInfoBlock*)&(LM(vi, vi->vmib_base)); + int window_size = vmib->WinSize * 1024; + int code; + int winnum; + + if(vi->windowA_offset >= 0) + if(vi->windowA_offset <= offset && vi->windowA_offset + window_size > offset) + if(vmib->WinAAttributes & purpose) + goto windowA; + + if(vi->windowB_offset >= 0) + if(vi->windowB_offset <= offset && vi->windowB_offset + window_size > offset) + if(vmib->WinBAttributes & purpose) + goto windowB; + + if(!(vmib->WinBAttributes & purpose) || + !(vmib->WinBAttributes & VBE_WINDOW_RELOCATE)) + goto set_windowA; + + if(!(vmib->WinAAttributes & purpose) || + !(vmib->WinAAttributes & VBE_WINDOW_RELOCATE)) + goto set_windowB; + + if(vi->last_window) + goto set_windowA; + else + goto set_windowB; + + set_windowA: + winnum = offset / (vmib->WinGranularity * 1024); + code = VbeReallySetWindow(vi, 0, winnum); + if(code < 0) { + ErrorF("Couldn't set window A to %d*%d\n", + (int)winnum, (int)vmib->WinGranularity); + return NULL; + } + vi->windowA_offset = winnum * vmib->WinGranularity * 1024; + windowA: + vi->last_window = 0; + *size_return = vmib->WinSize * 1024 - (offset - vi->windowA_offset); + return ((U8*)&(LM(vi, MAKE_POINTER(vmib->WinASegment, 0)))) + + offset - vi->windowA_offset; + + set_windowB: + winnum = offset / (vmib->WinGranularity * 1024); + code = VbeReallySetWindow(vi, 1, winnum); + if(code < 0) { + ErrorF("Couldn't set window B to %d*%d\n", + (int)winnum, (int)vmib->WinGranularity); + return NULL; + } + vi->windowB_offset = winnum * vmib->WinGranularity * 1024; + windowB: + vi->last_window = 1; + *size_return = vmib->WinSize * 1024 - (offset - vi->windowB_offset); + return ((U8*)&(LM(vi, MAKE_POINTER(vmib->WinBSegment, 0)))) + offset - vi->windowB_offset; +} + +int +VbeSetWritePlaneMask(VbeInfoPtr vi, int mask) +{ + asm volatile ("outb %b0,%w1" : : "a" (2), "d" (0x3c4)); + asm volatile ("outb %b0,%w1" : : "a" (mask), "d" (0x3c5)); +} + +int +VbeSetReadPlaneMap(VbeInfoPtr vi, int map) +{ + asm volatile ("outb %b0,%w1" : : "a" (4), "d" (0x3ce)); + asm volatile ("outb %b0,%w1" : : "a" (map), "d" (0x3cf)); +} + int VbeReportInfo(VbeInfoPtr vi, VbeInfoBlock *vib) { @@ -496,12 +659,12 @@ VbeReportInfo(VbeInfoPtr vi, VbeInfoBlock *vib) (vib->Capabilities[0]&1)?"fixed":"switchable", (vib->Capabilities[0]&2)?"not ":"", (vib->Capabilities[0]&3)?", RAMDAC causes snow":""); - ErrorF("Total memory: %lu bytes\n", 64L*vib->TotalMemory); + ErrorF("Total memory: %lu kilobytes\n", 64L*vib->TotalMemory); if(error) return -1; return 0; } - + int VbeReportModeInfo(VbeInfoPtr vi, U16 mode, VbeModeInfoBlock *vmib) { @@ -572,7 +735,7 @@ VbeDoInterrupt10(VbeInfoPtr vi) if(code < 0) return -1; - if((vi->vms.regs.eax & 0xFFFF) != 0x4F) { + if((vi->vms.regs.eax & 0xFFFF) != 0x4F && (oldax & 0xFF00) == 0x4F00) { ErrorF("Int 10h (0x%04X) failed: 0x%04X", oldax, vi->vms.regs.eax & 0xFFFF); if((oldax & 0xFF00) == 0x4F00) { @@ -627,7 +790,9 @@ VbeDoInterrupt(VbeInfoPtr vi, int num) PUSHW(vi, POINTER_OFFSET(vi->ret_code)); vi->vms.regs.cs = seg; vi->vms.regs.eip = off; + OsBlockSignals (); code = vm86_loop(vi); + OsReleaseSignals (); if(code < 0) { perror("vm86 failed"); return -1; @@ -873,6 +1038,7 @@ static int vm86_loop(VbeInfoPtr vi) { int code; + while(1) { code = vm86old(&vi->vms); switch(VM86_TYPE(code)) { @@ -1030,18 +1196,20 @@ static int vm86old(struct vm86_struct *vm) { int res; + asm volatile ( - "pushl %%ebx\n\t" - "movl %2, %%ebx\n\t" - "movl %1,%%eax\n\t" - "int $0x80\n\t" - "popl %%ebx" - : "=a" (res) : "n" (113), "r" (vm)); + "pushl %%ebx\n\t" + "movl %2, %%ebx\n\t" + "movl %1,%%eax\n\t" + "int $0x80\n\t" + "popl %%ebx" + : "=a" (res) : "n" (113), "r" (vm)); if(res < 0) { - errno = -res; - res = -1; + errno = -res; + res = -1; } else - errno = 0; + errno = 0; + OsReleaseSignals (); return res; } diff --git a/hw/kdrive/vesa/vbe.h b/hw/kdrive/vesa/vbe.h index c8041fd2e..b76e99ee7 100644 --- a/hw/kdrive/vesa/vbe.h +++ b/hw/kdrive/vesa/vbe.h @@ -23,6 +23,10 @@ THE SOFTWARE. #ifndef _VBE_H #define _VBE_H +#define VBE_WINDOW_RELOCATE 1 +#define VBE_WINDOW_READ 2 +#define VBE_WINDOW_WRITE 4 + #ifndef U8 #define U8 unsigned char #define U16 unsigned short @@ -61,13 +65,16 @@ THE SOFTWARE. typedef struct _VbeInfoRec { int devmem, devzero; - void *magicMem, *loMem, *hiMem, *fb; - U32 fb_size; + void *magicMem, *loMem, *hiMem; U32 brk; struct vm86_struct vms; U32 ret_code, stack_base, vib_base, vmib_base, statebuffer_base, palette_scratch_base; U8 palette_format; int palette_wait; + int windowA_offset; + int windowB_offset; + int last_window; + int vga_palette; } VbeInfoRec, *VbeInfoPtr; typedef struct _VbeInfoBlock { @@ -143,15 +150,16 @@ VbeInfoPtr VbeSetup(void); void VbeCleanup(VbeInfoPtr vi); VbeInfoBlock *VbeGetInfo(VbeInfoPtr vi); VbeModeInfoBlock *VbeGetModeInfo(VbeInfoPtr vi, int mode); -int VbeSetMode(VbeInfoPtr vi, int mode); +int VbeSetMode(VbeInfoPtr vi, int mode, int linear); int VbeGetMode(VbeInfoPtr vi, int *mode); int VbeSetupStateBuffer(VbeInfoPtr vi); int VbeSaveState(VbeInfoPtr vi); int VbeRestoreState(VbeInfoPtr vi); -void *VbeMapFramebuffer(VbeInfoPtr vi); -int VbeUnmapFrambuffer(VbeInfoPtr vi); +void *VbeMapFramebuffer(VbeInfoPtr vi, VbeModeInfoBlock *vmib); +int VbeUnmapFrambuffer(VbeInfoPtr vi, VbeModeInfoBlock *vmib, void *fb); int VbeSetPalette(VbeInfoPtr vi, int first, int number, U8 *entries); int VbeSetPaletteOptions(VbeInfoPtr vi, U8 bits, int wait); +void *VbeSetWindow(VbeInfoPtr vi, int offset, int purpose, int *size_return); int VbeReportInfo(VbeInfoPtr, VbeInfoBlock *); int VbeReportModeInfo(VbeInfoPtr, U16 mode, VbeModeInfoBlock *); diff --git a/hw/kdrive/vesa/vesa.c b/hw/kdrive/vesa/vesa.c index 0939dabab..48e39ec8c 100644 --- a/hw/kdrive/vesa/vesa.c +++ b/hw/kdrive/vesa/vesa.c @@ -22,11 +22,12 @@ THE SOFTWARE. #include "vesa.h" -#define DEFAULT_MODE 0x115 - -int vesa_video_mode = DEFAULT_MODE; +int vesa_video_mode = 0; Bool vesa_force_mode = FALSE; Bool vesa_swap_rgb = FALSE; +Bool vesa_shadow = FALSE; +Bool vesa_linear_fb = TRUE; +Bool vesa_restore = FALSE; static Bool vesaModeSupported(VbeInfoPtr vi, VbeModeInfoBlock *vmib, Bool complain) @@ -36,17 +37,19 @@ vesaModeSupported(VbeInfoPtr vi, VbeModeInfoBlock *vmib, Bool complain) ErrorF("Text mode specified.\n"); return FALSE; } - if(vmib->MemoryModel != 0x06 && vmib->MemoryModel != 0x04) { + if(vmib->MemoryModel != 0x06 && vmib->MemoryModel != 0x04 && vmib->MemoryModel != 0x03) { if(complain) ErrorF("Unsupported memory model 0x%X\n", vmib->MemoryModel); return FALSE; } if((vmib->ModeAttributes & 0x80) == 0) { - if(complain) - ErrorF("No linear framebuffer available in this mode\n"); - return FALSE; + if ((vmib->WinAAttributes & 0x5) != 0x5) { + if(complain) + ErrorF("Neither linear nor windowed framebuffer available in this mode\n"); + return FALSE; + } } - if(!(vmib->ModeAttributes&1)) { + if(!(vmib->ModeAttributes & 1)) { if(complain) ErrorF("Mode not supported on this hardware\n"); return FALSE; @@ -61,7 +64,8 @@ vesaListModes() VbeInfoPtr vi = NULL; VbeInfoBlock *vib; VbeModeInfoBlock *vmib; - unsigned i; + unsigned p, num_modes, i; + CARD16 *modes_list = NULL; vi = VbeSetup(); if(!vi) @@ -72,32 +76,91 @@ vesaListModes() goto fail; VbeReportInfo(vi, vib); - i = MAKE_POINTER_1(vib->VideoModePtr); - - while(VbeMemoryW(vi, i) != 0xFFFF) { - vmib = VbeGetModeInfo(vi, VbeMemoryW(vi, i)); + /* The spec says you need to copy the list */ + p = MAKE_POINTER_1(vib->VideoModePtr); + num_modes = 0; + while(VbeMemoryW(vi, p) != 0xFFFF) { + num_modes++; + p+=2; + } + modes_list = ALLOCATE_LOCAL(num_modes * sizeof(CARD16)); + if(!modes_list) + goto fail; + p = MAKE_POINTER_1(vib->VideoModePtr); + for(i=0; i<num_modes; i++) { + modes_list[i] = VbeMemoryW(vi, p); + p += 2; + } + + for(i=0; i<num_modes; i++) { + vmib = VbeGetModeInfo(vi, modes_list[i]); if(!vmib) goto fail; if(vesa_force_mode || vesaModeSupported(vi, vmib, FALSE)) - VbeReportModeInfo(vi, VbeMemoryW(vi, i), vmib); - i+=2; + VbeReportModeInfo(vi, modes_list[i], vmib); } + if(modes_list) + DEALLOCATE_LOCAL(modes_list); VbeCleanup(vi); return TRUE; fail: + if(modes_list) + DEALLOCATE_LOCAL(modes_list); VbeCleanup(vi); return FALSE; } Bool -vesaInitialize (KdCardInfo *card, VesaPrivPtr priv) +vesaGetModes (KdCardInfo *card, VesaCardPrivPtr priv) +{ + VesaModePtr mode; + int nmode; + unsigned int i; + VbeInfoPtr vi = priv->vi; + VbeInfoBlock *vib = priv->vib; + VbeModeInfoBlock *vmib; + + /* The spec says you need to copy the list */ + i = MAKE_POINTER_1(vib->VideoModePtr); + nmode = 0; + while(VbeMemoryW(vi, i) != 0xFFFF) { + nmode++; + i+=2; + } + if (!nmode) + return FALSE; + priv->modes = xalloc (nmode * sizeof (VesaModeRec)); + if (!priv->modes) + return FALSE; + priv->nmode = nmode; + i = MAKE_POINTER_1(vib->VideoModePtr); + nmode = 0; + while(nmode < priv->nmode) { + priv->modes[nmode].mode = VbeMemoryW(vi, i); + nmode++; + i+=2; + } + i = MAKE_POINTER_1(vib->VideoModePtr); + nmode = 0; + while(nmode < priv->nmode) { + vmib = VbeGetModeInfo(vi, priv->modes[nmode].mode); + if(!vmib) + break; + priv->modes[nmode].vmib = *vmib; + i += 2; + nmode++; + } + return TRUE; +} + + +Bool +vesaInitialize (KdCardInfo *card, VesaCardPrivPtr priv) { int code; - priv->mode = vesa_video_mode; - priv->vi = VbeSetup(); if(!priv->vi) goto fail; @@ -106,13 +169,6 @@ vesaInitialize (KdCardInfo *card, VesaPrivPtr priv) if(!priv->vib) goto fail; - priv->vmib = VbeGetModeInfo(priv->vi, priv->mode); - if(!priv->vmib) - goto fail; - - if(!vesa_force_mode && !vesaModeSupported(priv->vi, priv->vmib, TRUE)) - goto fail; - code = VbeSetupStateBuffer(priv->vi); if(code < 0) goto fail; @@ -121,10 +177,9 @@ vesaInitialize (KdCardInfo *card, VesaPrivPtr priv) if(code<0) goto fail; - priv->fb = VbeMapFramebuffer(priv->vi); - if(!priv->vi) - goto fail; - + if (!vesaGetModes (card, priv)) + goto fail; + card->driver = priv; return TRUE; @@ -138,9 +193,9 @@ vesaInitialize (KdCardInfo *card, VesaPrivPtr priv) Bool vesaCardInit(KdCardInfo *card) { - VesaPrivPtr priv; + VesaCardPrivPtr priv; - priv = xalloc(sizeof(VesaPrivRec)); + priv = xalloc(sizeof(VesaCardPrivRec)); if(!priv) return FALSE; @@ -153,30 +208,137 @@ vesaCardInit(KdCardInfo *card) return TRUE; } +int +vesaDepth (VbeModeInfoBlock *m) +{ + if (m->MemoryModel == 0x06) + return (m->RedMaskSize + + m->GreenMaskSize + + m->BlueMaskSize); + else + return m->BitsPerPixel; +} + Bool -vesaScreenInit(KdScreenInfo *screen) +vesaModeGood (KdScreenInfo *screen, + VbeModeInfoBlock *a) { - VesaPrivPtr priv = screen->card->driver; + if (a->XResolution <= screen->width && + a->YResolution <= screen->height && + vesaDepth (a) >= screen->fb[0].depth) + { + return TRUE; + } +} + +#define vabs(a) ((a) >= 0 ? (a) : -(a)) + +int +vesaSizeError (KdScreenInfo *screen, + VbeModeInfoBlock *a) +{ + int xdist, ydist; + xdist = vabs (screen->width - a->XResolution); + ydist = vabs (screen->height - a->YResolution); + return xdist * xdist + ydist * ydist; +} + +Bool +vesaModeBetter (KdScreenInfo *screen, + VbeModeInfoBlock *a, + VbeModeInfoBlock *b) +{ + int aerr, berr; + + if (vesaModeGood (screen, a)) + { + if (!vesaModeGood (screen, b)) + return TRUE; + } + else + { + if (vesaModeGood (screen, b)) + return FALSE; + } + aerr = vesaSizeError (screen, a); + berr = vesaSizeError (screen, b); + if (aerr < berr) + return TRUE; + if (berr < aerr) + return FALSE; + if (vabs (screen->fb[0].depth - vesaDepth (a)) < + vabs (screen->fb[0].depth - vesaDepth (b))) + return TRUE; + return FALSE; +} + +VesaModePtr +vesaSelectMode (KdScreenInfo *screen) +{ + VesaCardPrivPtr priv = screen->card->driver; + int i, best; + + if (vesa_video_mode) + { + for (best = 0; best < priv->nmode; best++) + if (priv->modes[best].mode == vesa_video_mode && + (vesaModeSupported (priv->vi, &priv->modes[best].vmib, FALSE) || + vesa_force_mode)) + return &priv->modes[best]; + } + for (best = 0; best < priv->nmode; best++) + { + if (vesaModeSupported (priv->vi, &priv->modes[best].vmib, FALSE)) + break; + } + if (best == priv->nmode) + return 0; + for (i = best + 1; i < priv->nmode; i++) + if (vesaModeSupported (priv->vi, &priv->modes[i].vmib, FALSE) && + vesaModeBetter (screen, &priv->modes[i].vmib, + &priv->modes[best].vmib)) + best = i; + return &priv->modes[best]; +} + +Bool +vesaScreenInitialize (KdScreenInfo *screen, VesaScreenPrivPtr pscr) +{ + VesaCardPrivPtr priv = screen->card->driver; + VbeModeInfoBlock *vmib; Pixel allbits; int depth; - screen->width = priv->vmib->XResolution; - screen->height = priv->vmib->YResolution; - screen->fb[0].depth = priv->vmib->BitsPerPixel; - screen->fb[0].bitsPerPixel = priv->vmib->BitsPerPixel; - screen->fb[0].byteStride = priv->vmib->BytesPerScanLine; - screen->fb[0].pixelStride = - (priv->vmib->BytesPerScanLine * 8) / priv->vmib->BitsPerPixel; + pscr->mode = vesaSelectMode (screen); + if (!pscr->mode) + return FALSE; - if(priv->vmib->MemoryModel == 0x06) { + pscr->shadow = vesa_shadow; + if (vesa_linear_fb) + pscr->mapping = VESA_LINEAR; + else + pscr->mapping = VESA_WINDOWED; + + vmib = &pscr->mode->vmib; + + screen->width = vmib->XResolution; + screen->height = vmib->YResolution; + screen->fb[0].depth = vesaDepth (vmib); + screen->fb[0].bitsPerPixel = vmib->BitsPerPixel; + screen->fb[0].byteStride = vmib->BytesPerScanLine; + screen->fb[0].pixelStride = ((vmib->BytesPerScanLine * 8) / + vmib->BitsPerPixel); + + switch (vmib->MemoryModel) { + case 0x06: /* TrueColor or DirectColor */ screen->fb[0].visuals = (1 << TrueColor); screen->fb[0].redMask = - FbStipMask(priv->vmib->RedFieldPosition, priv->vmib->RedMaskSize); + FbStipMask(vmib->RedFieldPosition, vmib->RedMaskSize); screen->fb[0].greenMask = - FbStipMask(priv->vmib->GreenFieldPosition, priv->vmib->GreenMaskSize); + FbStipMask(vmib->GreenFieldPosition, vmib->GreenMaskSize); screen->fb[0].blueMask = - FbStipMask(priv->vmib->BlueFieldPosition, priv->vmib->BlueMaskSize); + FbStipMask(vmib->BlueFieldPosition, vmib->BlueMaskSize); allbits = screen->fb[0].redMask | screen->fb[0].greenMask | @@ -185,7 +347,8 @@ vesaScreenInit(KdScreenInfo *screen) while (depth && !(allbits & (1 << (depth - 1)))) depth--; screen->fb[0].depth = depth; - } else if (priv->vmib->MemoryModel == 0x04) { + break; + case 0x04: /* PseudoColor */ screen->fb[0].visuals = ((1 << StaticGray) | (1 << GrayScale) | @@ -196,35 +359,204 @@ vesaScreenInit(KdScreenInfo *screen) screen->fb[0].blueMask = 0x00; screen->fb[0].greenMask = 0x00; screen->fb[0].redMask = 0x00; - } else { + break; + case 0x03: + /* 4 plane planar */ + screen->fb[0].visuals = (1 << StaticColor); + screen->fb[0].blueMask = 0x00; + screen->fb[0].greenMask = 0x00; + screen->fb[0].redMask = 0x00; + screen->fb[0].depth = 4; + screen->fb[0].bitsPerPixel = 4; + pscr->mapping = VESA_PLANAR; + break; + default: ErrorF("Unsupported VESA MemoryModel 0x%02X\n", - priv->vmib->MemoryModel); + vmib->MemoryModel); return FALSE; } + if (pscr->mapping == VESA_LINEAR && !(vmib->ModeAttributes & 0x80)) + pscr->mapping = VESA_WINDOWED; + + switch (pscr->mapping) { + case VESA_LINEAR: + pscr->fb = VbeMapFramebuffer(priv->vi, vmib); + break; + case VESA_WINDOWED: + pscr->fb = NULL; + pscr->shadow = TRUE; + break; + case VESA_PLANAR: + pscr->fb = NULL; + pscr->shadow = TRUE; + break; + } + screen->rate = 72; - screen->fb[0].frameBuffer = (CARD8 *)(priv->fb); + screen->fb[0].frameBuffer = (CARD8 *)(pscr->fb); + + if (pscr->shadow) + return KdShadowScreenInit (screen); + + return TRUE; +} + +Bool +vesaScreenInit(KdScreenInfo *screen) +{ + VesaScreenPrivPtr pscr; + + pscr = xcalloc (1, sizeof (VesaScreenPrivRec)); + if (!pscr) + return FALSE; + if (!vesaScreenInitialize (screen, pscr)) + return FALSE; + screen->driver = pscr; + return TRUE; +} + +void * +vesaWindowPlanar (ScreenPtr pScreen, + CARD32 row, + CARD32 offset, + int mode, + CARD32 *size) +{ + KdScreenPriv(pScreen); + VesaCardPrivPtr priv = pScreenPriv->card->driver; + VesaScreenPrivPtr pscr = pScreenPriv->screen->driver; + VbeModeInfoBlock *vmib = &pscr->mode->vmib; + static int plane; + int winSize; + void *base; + + if (!pScreenPriv->enabled) + return 0; + plane = offset & 3; + VbeSetWritePlaneMask (priv->vi, (1 << plane)); + offset = offset >> 2; + base = VbeSetWindow (priv->vi, + vmib->BytesPerScanLine * row + offset, + mode, + &winSize); + *size = (CARD32) winSize; + return base; +} + +void * +vesaWindowLinear (ScreenPtr pScreen, + CARD32 row, + CARD32 offset, + int mode, + CARD32 *size) +{ + KdScreenPriv(pScreen); + VesaCardPrivPtr priv = pScreenPriv->card->driver; + VesaScreenPrivPtr pscr = pScreenPriv->screen->driver; + VbeModeInfoBlock *vmib = &pscr->mode->vmib; + + if (!pScreenPriv->enabled) + return 0; + *size = vmib->BytesPerScanLine; + return (CARD8 *) pscr->fb + row * vmib->BytesPerScanLine + offset; +} + +void * +vesaWindowWindowed (ScreenPtr pScreen, + CARD32 row, + CARD32 offset, + int mode, + CARD32 *size) +{ + KdScreenPriv(pScreen); + VesaCardPrivPtr priv = pScreenPriv->card->driver; + VesaScreenPrivPtr pscr = pScreenPriv->screen->driver; + VbeModeInfoBlock *vmib = &pscr->mode->vmib; + int winSize; + void *base; + + if (!pScreenPriv->enabled) + return 0; + base = VbeSetWindow (priv->vi, + vmib->BytesPerScanLine * row + offset, + mode, + &winSize); + *size = (CARD32) winSize; + return base; +} + +static CARD16 vga16Colors[16][3] = { + { 0, 0, 0, }, /* 0 */ + { 0x80,0, 0, }, /* 1 */ + { 0, 0x80,0, }, /* 2 */ + { 0x80,0x80,0, }, /* 3 */ + { 0, 0, 0x80,}, /* 4 */ + { 0x80,0, 0x80,}, /* 5 */ + { 0, 0x80,0x80,}, /* 6 */ + { 0x80,0x80,0x80,}, /* 7 */ + { 0xC0,0xC0,0xC0,}, /* 8 */ + { 0xFF,0, 0 ,}, /* 9 */ + { 0, 0xFF,0 ,}, /* 10 */ + { 0xFF,0xFF,0 ,}, /* 11 */ + { 0 ,0, 0xFF,}, /* 12 */ + { 0xFF,0, 0xFF,}, /* 13 */ + { 0, 0xFF,0xFF,}, /* 14 */ + { 0xFF,0xFF,0xFF,}, /* 15 */ +}; + +Bool +vesaCreateColormap16 (ColormapPtr pmap) +{ + int i; + for (i = 0; i < 16; i++) + { + pmap->red[i].co.local.red = (vga16Colors[i][0]<<8)|vga16Colors[i][0]; + pmap->red[i].co.local.green = (vga16Colors[i][1]<<8)|vga16Colors[i][1]; + pmap->red[i].co.local.blue = (vga16Colors[i][2]<<8)|vga16Colors[i][2]; + } return TRUE; } + Bool vesaInitScreen(ScreenPtr pScreen) { + KdScreenPriv(pScreen); + VesaScreenPrivPtr pscr = pScreenPriv->screen->driver; + + if (pscr->shadow) + { + switch (pscr->mapping) { + case VESA_LINEAR: + return KdShadowInitScreen (pScreen, shadowUpdatePacked, vesaWindowLinear); + case VESA_WINDOWED: + return KdShadowInitScreen (pScreen, shadowUpdatePacked, vesaWindowWindowed); + case VESA_PLANAR: + pScreen->CreateColormap = vesaCreateColormap16; + return KdShadowInitScreen (pScreen, shadowUpdatePlanar4, vesaWindowPlanar); + } + } + return TRUE; } -void +Bool vesaEnable(ScreenPtr pScreen) { KdScreenPriv(pScreen); - VesaPrivPtr priv = pScreenPriv->card->driver; + VesaCardPrivPtr priv = pScreenPriv->card->driver; + VesaScreenPrivPtr pscr = pScreenPriv->screen->driver; int code; int palette_wait = 0, palette_hi = 0; + int i=0; + int size; + char *p; - code = VbeSetMode(priv->vi, priv->mode); + code = VbeSetMode(priv->vi, pscr->mode->mode, pscr->mapping == VESA_LINEAR); if(code < 0) - FatalError("Couldn't set mode\n"); + return FALSE; if(priv->vib->Capabilities[0] & 1) palette_hi = 1; @@ -233,23 +565,85 @@ vesaEnable(ScreenPtr pScreen) if(palette_hi || palette_wait) VbeSetPaletteOptions(priv->vi, palette_hi?8:6, palette_wait); - return; + switch (pscr->mapping) { + case VESA_LINEAR: + memcpy (priv->text, pscr->fb, VESA_TEXT_SAVE); + break; + case VESA_WINDOWED: + while(i < VESA_TEXT_SAVE) { + p = VbeSetWindow(priv->vi, i, VBE_WINDOW_READ, &size); + if(!p) { + ErrorF("Couldn't set window for saving VGA font\n"); + break; + } + if(i + size > VESA_TEXT_SAVE) + size = VESA_TEXT_SAVE - i; + memcpy(((char*)priv->text) + i, p, size); + i += size; + } + break; + case VESA_PLANAR: + p = VbeSetWindow (priv->vi, 0, VBE_WINDOW_READ, &size); + for (i = 0; i < 4; i++) + { + VbeSetReadPlaneMap (priv->vi, i); + memcpy (((char *)priv->text) + i * (VESA_TEXT_SAVE/4), p, + (VESA_TEXT_SAVE/4)); + } + break; + } + return TRUE; } void vesaDisable(ScreenPtr pScreen) { KdScreenPriv(pScreen); - VesaPrivPtr priv = pScreenPriv->card->driver; - + VesaCardPrivPtr priv = pScreenPriv->card->driver; + VesaScreenPrivPtr pscr = pScreenPriv->screen->driver; + int i=0; + int size; + char *p; + + switch (pscr->mapping) { + case VESA_LINEAR: + memcpy(pscr->fb, priv->text, VESA_TEXT_SAVE); + break; + case VESA_WINDOWED: + while(i < VESA_TEXT_SAVE) { + p = VbeSetWindow(priv->vi, i, VBE_WINDOW_WRITE, &size); + if(!p) { + ErrorF("Couldn't set window for restoring VGA font\n"); + break; + } + if(i + size > VESA_TEXT_SAVE) + size = VESA_TEXT_SAVE - i; + memcpy(p, ((char*)priv->text) + i, size); + i += size; + } + break; + case VESA_PLANAR: + p = VbeSetWindow (priv->vi, 0, VBE_WINDOW_WRITE, &size); + for (i = 0; i < 4; i++) + { + VbeSetWritePlaneMask (priv->vi, 1 << i); + memcpy (p, + ((char *)priv->text) + i * (VESA_TEXT_SAVE/4), + (VESA_TEXT_SAVE/4)); + } + break; + } } void vesaPreserve(KdCardInfo *card) { - VesaPrivPtr priv = card->driver; + VesaCardPrivPtr priv = card->driver; int code; + /* The framebuffer might not be valid at this point, so we cannot + save the VGA fonts now; we do it in vesaEnable. */ + code = VbeSaveState(priv->vi); if(code < 0) FatalError("Couldn't save state\n"); @@ -260,7 +654,7 @@ vesaPreserve(KdCardInfo *card) void vesaRestore(KdCardInfo *card) { - VesaPrivPtr priv = card->driver; + VesaCardPrivPtr priv = card->driver; VbeRestoreState(priv->vi); return; } @@ -268,8 +662,9 @@ vesaRestore(KdCardInfo *card) void vesaCardFini(KdCardInfo *card) { - VesaPrivPtr priv = card->driver; - VbeUnmapFramebuffer(priv->vi); + VesaCardPrivPtr priv = card->driver; + if (vesa_restore) + VbeSetTextMode(priv->vi,3); VbeCleanup(priv->vi); return; } @@ -277,15 +672,21 @@ vesaCardFini(KdCardInfo *card) void vesaScreenFini(KdScreenInfo *screen) { - return; + VesaScreenPrivPtr pscr = screen->driver; + VesaCardPrivPtr priv = screen->card->driver; + + if (pscr->fb) + VbeUnmapFramebuffer(priv->vi, &pscr->mode->vmib, pscr->fb); + return; } void vesaPutColors (ScreenPtr pScreen, int fb, int n, xColorItem *pdefs) { KdScreenPriv(pScreen); - VesaPrivPtr priv = pScreenPriv->card->driver; - int i, j, k; + VesaScreenPrivPtr pscr = pScreenPriv->screen->driver; + VesaCardPrivPtr priv = pScreenPriv->card->driver; + int i, j, k, start; CARD8 scratch[4*256]; int red, green, blue; @@ -314,7 +715,14 @@ vesaPutColors (ScreenPtr pScreen, int fb, int n, xColorItem *pdefs) scratch[k+blue] = pdefs[i+k].blue >> 8; scratch[k+3] = 0; } - VbeSetPalette(priv->vi, pdefs[i].pixel, j - i, scratch); + start = pdefs[i].pixel; + if (pscr->mapping == VESA_PLANAR) + { + for (start = pdefs[i].pixel; start < 256; start += 16) + VbeSetPalette(priv->vi, start, j - i, scratch); + } + else + VbeSetPalette(priv->vi, start, j - i, scratch); i = j; } } @@ -323,7 +731,7 @@ void vesaGetColors (ScreenPtr pScreen, int fb, int n, xColorItem *pdefs) { KdScreenPriv(pScreen); - VesaPrivPtr priv = pScreenPriv->card->driver; + VesaCardPrivPtr priv = pScreenPriv->card->driver; int first, i, j, k; CARD8 scratch[4]; int red, green, blue; @@ -367,6 +775,15 @@ vesaProcessArgument (int argc, char **argv, int i) } else if(!strcmp(argv[i], "-swaprgb")) { vesa_swap_rgb = TRUE; return 1; + } else if(!strcmp(argv[i], "-shadow")) { + vesa_shadow = TRUE; + return 1; + } else if(!strcmp(argv[i], "-nolinear")) { + vesa_linear_fb = FALSE; + return 1; + } else if(!strcmp(argv[i], "-restore")) { + vesa_restore = TRUE; + return 1; } return 0; diff --git a/hw/kdrive/vesa/vesa.h b/hw/kdrive/vesa/vesa.h index 453b36f2e..256146cad 100644 --- a/hw/kdrive/vesa/vesa.h +++ b/hw/kdrive/vesa/vesa.h @@ -27,24 +27,42 @@ THE SOFTWARE. #include <sys/vm86.h> #include "vbe.h" -typedef struct _VesaPriv { +#define VESA_TEXT_SAVE (64*1024) + +typedef struct _VesaMode { int mode; + VbeModeInfoBlock vmib; +} VesaModeRec, *VesaModePtr; + +typedef struct _VesaCardPriv { VbeInfoPtr vi; VbeInfoBlock *vib; - VbeModeInfoBlock *vmib; + VesaModePtr modes; + int nmode; + char text[VESA_TEXT_SAVE]; +} VesaCardPrivRec, *VesaCardPrivPtr; + +#define VESA_LINEAR 0 +#define VESA_WINDOWED 1 +#define VESA_PLANAR 2 +typedef struct _VesaScreenPriv { + VesaModePtr mode; + Bool shadow; + int mapping; void *fb; -} VesaPrivRec, *VesaPrivPtr; +} VesaScreenPrivRec, *VesaScreenPrivPtr; extern int vesa_video_mode; extern Bool vesa_force_mode; Bool vesaListModes(void); -Bool vesaInitialize(KdCardInfo *card, VesaPrivPtr priv); +Bool vesaInitialize(KdCardInfo *card, VesaCardPrivPtr priv); Bool vesaCardInit(KdCardInfo *card); -Bool vesaInitialize (KdCardInfo *card, VesaPrivPtr priv); -Bool vesaScreenInit(KdScreenInfo *screen); +Bool vesaInitialize (KdCardInfo *card, VesaCardPrivPtr priv); +Bool vesaScreenInitialize (KdScreenInfo *screen, VesaScreenPrivPtr pscr); +Bool vesaScreenInit(KdScreenInfo *screen); Bool vesaInitScreen(ScreenPtr pScreen); -void vesaEnable(ScreenPtr pScreen); +Bool vesaEnable(ScreenPtr pScreen); void vesaDisable(ScreenPtr pScreen); void vesaPreserve(KdCardInfo *card); void vesaRestore(KdCardInfo *card); |