diff options
Diffstat (limited to 'xorg-server/hw/kdrive/vesa/vbe.c')
-rw-r--r-- | xorg-server/hw/kdrive/vesa/vbe.c | 706 |
1 files changed, 706 insertions, 0 deletions
diff --git a/xorg-server/hw/kdrive/vesa/vbe.c b/xorg-server/hw/kdrive/vesa/vbe.c new file mode 100644 index 000000000..cedefe9fc --- /dev/null +++ b/xorg-server/hw/kdrive/vesa/vbe.c @@ -0,0 +1,706 @@ +/* +Copyright (c) 2000 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifdef HAVE_CONFIG_H +#include <kdrive-config.h> +#endif +#include "vesa.h" + +int +VbeGetVib (Vm86InfoPtr vi, VbeInfoBlock *vib) +{ + int code; + int mark; + int vib_base; + VbeInfoBlock *vib_low; + + mark = Vm86MarkMemory (vi); + vib_base = Vm86AllocateMemory (vi, sizeof (VbeInfoBlock)); + vib_low = (VbeInfoBlock*)&(LM(vi, vib_base)); + vi->vms.regs.eax = 0x4F00; + vi->vms.regs.es = POINTER_SEGMENT(vib_base); + vi->vms.regs.edi = POINTER_OFFSET(vib_base); + memcpy(vib_low->VbeSignature, "VBE2", 4); + code = VbeDoInterrupt10(vi); + if(code >= 0) + { + if(memcmp(vib_low->VbeSignature, "VESA", 4) == 0) + *vib = *vib_low; + else + code = -1; + } + Vm86ReleaseMemory (vi, mark); + return code; +} + +int +VbeGetVmib (Vm86InfoPtr vi, int mode, VbeModeInfoBlock *vmib) +{ + int code; + int mark; + int vmib_base; + VbeModeInfoBlock *vmib_low; + + mark = Vm86MarkMemory (vi); + + vmib_base = Vm86AllocateMemory (vi, sizeof (VbeModeInfoBlock)); + vmib_low = (VbeModeInfoBlock*)&(LM(vi, vmib_base)); + + vi->vms.regs.eax = 0x4F01; + vi->vms.regs.ecx = mode&0xFFFF; + vi->vms.regs.es = POINTER_SEGMENT(vmib_base); + vi->vms.regs.edi = POINTER_OFFSET(vmib_base); + code = VbeDoInterrupt10(vi); + + if(code >= 0) + *vmib = *vmib_low; + Vm86ReleaseMemory (vi, mark); + return code; +} + +static int +VbeReportVib(Vm86InfoPtr vi, VbeInfoBlock *vib) +{ + U32 i, p; + unsigned char c; + int error = 0; + + ErrorF("VBE version %c.%c (", + ((vib->VbeVersion >> 8) & 0xFF) + '0', + (vib->VbeVersion & 0xFF)+'0'); + p = vib->OemStringPtr; + for(i = 0; 1; i++) { + c = Vm86Memory(vi, MAKE_POINTER_1(p+i)); + if(!c) break; + if (c >= ' ') + ErrorF("%c", c); + if (i > 32000) { + error = 1; + break; + } + } + ErrorF(")\n"); + ErrorF("DAC is %s, controller is %sVGA compatible%s\n", + (vib->Capabilities[0]&1)?"switchable":"fixed", + (vib->Capabilities[0]&2)?"not ":"", + (vib->Capabilities[0]&3)?", RAMDAC causes snow":""); + ErrorF("Total memory: %lu kilobytes\n", 64L*vib->TotalMemory); + if(error) + return -1; + return 0; +} + +#if 0 +static int +VbeReportModeInfo(Vm86InfoPtr vi, U16 mode, VbeModeInfoBlock *vmib) +{ + int supported = (vmib->ModeAttributes&0x1)?1:0; + int colour = (vmib->ModeAttributes&0x8)?1:0; + int graphics = (vmib->ModeAttributes&0x10)?1:0; + int vga_compatible = !((vmib->ModeAttributes&0x20)?1:0); + int linear_fb = (vmib->ModeAttributes&0x80)?1:0; + + ErrorF("0x%04X: %dx%dx%d%s", + (unsigned)mode, + (int)vmib->XResolution, (int)vmib->YResolution, + (int)vmib->BitsPerPixel, + colour?"":" (monochrome)", + graphics?"":" (graphics)", + vga_compatible?"":" (vga compatible)", + linear_fb?"":" (linear frame buffer)"); + switch(vmib->MemoryModel) { + case 0: + ErrorF(" text mode (%dx%d)", + (int)vmib->XCharSize, (int)vmib->YCharSize); + break; + case 1: + ErrorF(" CGA graphics"); + break; + case 2: + ErrorF(" Hercules graphics"); + break; + case 3: + ErrorF(" Planar (%d planes)", vmib->NumberOfPlanes); + break; + case 4: + ErrorF(" PseudoColor"); + break; + case 5: + ErrorF(" Non-chain 4, 256 colour"); + break; + case 6: + if(vmib->DirectColorModeInfo & 1) + ErrorF(" DirectColor"); + else + ErrorF(" TrueColor"); + ErrorF(" [%d:%d:%d:%d]", + vmib->RedMaskSize, vmib->GreenMaskSize, vmib->BlueMaskSize, + vmib->RsvdMaskSize); + if(vmib->DirectColorModeInfo & 2) + ErrorF(" (reserved bits are reserved)"); + break; + case 7: ErrorF("YUV"); + break; + default: + ErrorF("unknown MemoryModel 0x%X ", vmib->MemoryModel); + } + if(!supported) + ErrorF(" (unsupported)"); + else if(!linear_fb) + ErrorF(" (no linear framebuffer)"); + ErrorF("\n"); + return 0; +} +#endif + +void +VbeReportInfo (Vm86InfoPtr vi) +{ + VbeInfoBlock vib; + int code; + + code = VbeGetVib (vi, &vib); + if (code >= 0) + VbeReportVib(vi, &vib); +} + +int +VbeGetNmode (Vm86InfoPtr vi) +{ + VbeInfoBlock vib; + int code; + unsigned int p; + int n; + int mode; + + code = VbeGetVib (vi, &vib); + if (code >= 0) + { + p = MAKE_POINTER_1(vib.VideoModePtr); + for (n = 0; ; n++) + { + mode = Vm86MemoryW(vi, p); + if (mode == 0xffff) + break; + p += 2; + } + code = n; + } + return code; +} + +int +VbeGetModes (Vm86InfoPtr vi, VesaModePtr modes, int nmode) +{ + VbeInfoBlock vib; + int code; + unsigned int p; + int n; + int mode; + VbeModeInfoBlock vmib; + + code = VbeGetVib (vi, &vib); + if (code < 0) + return code; + + memset (modes, '\0', nmode * sizeof (VesaModeRec)); + + p = MAKE_POINTER_1(vib.VideoModePtr); + for (n = 0; n < nmode; n++) + { + mode = Vm86MemoryW(vi, p); + if (mode == 0xffff) + break; + modes[n].mode = mode; + modes[n].vbe = 1; + p += 2; + } + + nmode = n; + + for (n = 0; n < nmode; n++) + { + code = VbeGetVmib (vi, modes[n].mode, &vmib); + if (code >= 0) + { + modes[n].ModeAttributes = vmib.ModeAttributes; + modes[n].NumberOfPlanes = vmib.NumberOfPlanes; + modes[n].BitsPerPixel = vmib.BitsPerPixel; + modes[n].MemoryModel = vmib.MemoryModel; + modes[n].RedMaskSize = vmib.RedMaskSize; + modes[n].RedFieldPosition = vmib.RedFieldPosition; + modes[n].GreenMaskSize = vmib.GreenMaskSize; + modes[n].GreenFieldPosition = vmib.GreenFieldPosition; + modes[n].BlueMaskSize = vmib.BlueMaskSize; + modes[n].BlueFieldPosition = vmib.BlueFieldPosition; + modes[n].RsvdMaskSize = vmib.RsvdMaskSize; + modes[n].RsvdFieldPosition = vmib.RsvdFieldPosition; + modes[n].DirectColorModeInfo = vmib.DirectColorModeInfo; + modes[n].XResolution = vmib.XResolution; + modes[n].YResolution = vmib.YResolution; + modes[n].BytesPerScanLine = vmib.BytesPerScanLine; + } + } + + return nmode; +} + +VbeInfoPtr +VbeInit (Vm86InfoPtr vi) +{ + VbeInfoPtr vbe; + int code; + VbeInfoBlock vib; + + code = VbeGetVib (vi, &vib); + if (code < 0) + return 0; + + vbe = xalloc (sizeof (VbeInfoRec)); + if (!vbe) + return 0; + vbe->palette_format = 6; + vbe->palette_wait = TRUE; + return vbe; +} + +void +VbeCleanup (Vm86InfoPtr vi, VbeInfoPtr vbe) +{ + xfree (vbe); +} + +int +VbeSetMode (Vm86InfoPtr vi, VbeInfoPtr vbe, int mode, int linear, int direct) +{ + int code; + VbeInfoBlock vib; + int palette_wait = 0, palette_hi = 0; + + code = VbeGetVib (vi, &vib); + if (code < 0) + return -1; + + code = VbeGetVmib (vi, mode, &vbe->vmib); + if (code < 0) + return -1; + + mode = (mode & 0xffff) &~ 0x8000; + if (linear) + mode |= 0x4000; + + vi->vms.regs.eax = 0x4F02; + vi->vms.regs.ebx = mode; + code = VbeDoInterrupt10(vi); + if(code < 0) + return -1; + + vbe->windowA_offset = vbe->windowB_offset = -1; + vbe->last_window = 1; + + if (!direct) + { + if(vib.Capabilities[0] & 1) + palette_hi = 1; + if(vib.Capabilities[0] & 4) + palette_wait = 1; + + if(palette_hi || palette_wait) + VbeSetPaletteOptions(vi, vbe, palette_hi?8:6, palette_wait); + } + + return 0; +} + +int +VbeGetMode(Vm86InfoPtr vi, int *mode) +{ + int code; + + vi->vms.regs.eax = 0x4F03; + code = VbeDoInterrupt10(vi); + if(code < 0) + return - 1; + *mode = vi->vms.regs.ebx & 0xFFFF; + return 0; +} + +void * +VbeMapFramebuffer(Vm86InfoPtr vi, VbeInfoPtr vbe, int mode, int *ret_size, CARD32 *ret_phys) +{ + U8 *fb; + VbeInfoBlock vib; + VbeModeInfoBlock vmib; + int size; + int pagesize = getpagesize(); + int before, after; + + if (VbeGetVib (vi, &vib) < 0) + return 0; + + if (VbeGetVmib (vi, mode, &vmib) < 0) + return 0; + + size = 1024 * 64L * vib.TotalMemory; + + *ret_size = size; + *ret_phys = vmib.PhysBasePtr; + + before = vmib.PhysBasePtr % pagesize; + after = pagesize - ((vmib.PhysBasePtr + size) % pagesize); + if(after == pagesize) + after = 0; + + fb = KdMapDevice (vmib.PhysBasePtr - before, before + size + after); + + if(fb == 0) + { + ErrorF("Failed to map framebuffer\n"); + return NULL; + } + + KdSetMappedMode (vmib.PhysBasePtr - before, before + size + after, + KD_MAPPED_MODE_FRAMEBUFFER); + + return fb + before; +} + +void +VbeUnmapFramebuffer(Vm86InfoPtr vi, VbeInfoPtr vbe, int mode, void *fb) +{ + VbeInfoBlock vib; + VbeModeInfoBlock vmib; + int size; + int pagesize = getpagesize(); + int before, after; + + if (VbeGetVib (vi, &vib) < 0) + return; + + if (VbeGetVmib (vi, mode, &vmib) < 0) + return; + + 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); + + KdUnmapDevice (fb, before + size + after); + KdResetMappedMode (vmib.PhysBasePtr - before, before + size + after, + KD_MAPPED_MODE_FRAMEBUFFER); +} + +int +VbeSetPalette(Vm86InfoPtr vi, VbeInfoPtr vbe, int first, int number, U8 *entries) +{ + U8 *palette_scratch; + int mark; + int palette_base; + int i, code; + + if(number == 0) + return 0; + + if(first < 0 || number < 0 || first + number > 256) { + ErrorF("Cannot set %d, %d palette entries\n", first, number); + return -1; + } + if(vbe->palette_format < 6 || vbe->palette_format > 8) { + ErrorF("Impossible palette format %d\n", vbe->palette_format); + return -1; + } + + mark = Vm86MarkMemory (vi); + palette_base = Vm86AllocateMemory (vi, 4 * 256); + + palette_scratch = &LM(vi, palette_base); + + for(i=0; i<number*4; i++) + palette_scratch[i] = entries[i] >> (8 - vbe->palette_format); + + vi->vms.regs.eax = 0x4F09; + if(vbe->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(palette_base); + vi->vms.regs.edi = POINTER_OFFSET(palette_base); + code = VbeDoInterrupt10(vi); + Vm86ReleaseMemory (vi, mark); + + if(code < 0) + return -1; + return 0; +} + +int +VbeGetPalette(Vm86InfoPtr vi, VbeInfoPtr vbe, int first, int number, U8 *entries) +{ + U8 *palette_scratch; + int mark; + int palette_base; + int i, code; + + if(number == 0) + return 0; + + if(first < 0 || number < 0 || first + number > 256) { + ErrorF("Cannot get %d, %d palette entries\n", first, number); + return -1; + } + if(vbe->palette_format < 6 || vbe->palette_format > 8) { + ErrorF("Impossible palette format %d\n", vbe->palette_format); + return -1; + } + + mark = Vm86MarkMemory (vi); + palette_base = Vm86AllocateMemory (vi, 4 * 256); + + palette_scratch = &LM(vi, palette_base); + + 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(palette_base); + vi->vms.regs.edi = POINTER_OFFSET(palette_base); + code = VbeDoInterrupt10(vi); + if(code >= 0) + { + for(i=0; i<number*4; i++) + entries[i] = palette_scratch[i] << (8-vbe->palette_format); + } + Vm86ReleaseMemory (vi, mark); + + return 0; +} + +int +VbeSetPaletteOptions(Vm86InfoPtr vi, VbeInfoPtr vbe, U8 bits, int wait) +{ + int code; + + if(bits < 6 || bits > 8) { + ErrorF("Impossible palette format %d\n", bits); + return -1; + } + if(bits != vbe->palette_format) + { + vbe->palette_format = 0; + vi->vms.regs.eax = 0x4F08; + vi->vms.regs.ebx = bits << 8; + code = VbeDoInterrupt10(vi); + if(code < 0) + return -1; + vbe->palette_format = bits; + } + vbe->palette_wait = wait; + return 0; +} + +static int +VbeReallySetWindow(Vm86InfoPtr 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(Vm86InfoPtr vi, VbeInfoPtr vbe, int offset, int purpose, int *size_return) +{ + int window_size = vbe->vmib.WinSize * 1024; + int code; + int winnum; + + if(vbe->windowA_offset >= 0) + if(vbe->windowA_offset <= offset && vbe->windowA_offset + window_size > offset) + if(vbe->vmib.WinAAttributes & purpose) + goto windowA; + + if(vbe->windowB_offset >= 0) + if(vbe->windowB_offset <= offset && vbe->windowB_offset + window_size > offset) + if(vbe->vmib.WinBAttributes & purpose) + goto windowB; + + if(!(vbe->vmib.WinBAttributes & purpose) || + !(vbe->vmib.WinBAttributes & VBE_WINDOW_RELOCATE)) + goto set_windowA; + + if(!(vbe->vmib.WinAAttributes & purpose) || + !(vbe->vmib.WinAAttributes & VBE_WINDOW_RELOCATE)) + goto set_windowB; + + if(vbe->last_window) + goto set_windowA; + else + goto set_windowB; + +set_windowA: + winnum = offset / (vbe->vmib.WinGranularity * 1024); + code = VbeReallySetWindow(vi, 0, winnum); + if(code < 0) { + ErrorF("Couldn't set window A to %d*%d\n", + (int)winnum, (int)vbe->vmib.WinGranularity); + return NULL; + } + vbe->windowA_offset = winnum * vbe->vmib.WinGranularity * 1024; +windowA: + vbe->last_window = 0; + *size_return = vbe->vmib.WinSize * 1024 - (offset - vbe->windowA_offset); + return ((U8*)&(LM(vi, MAKE_POINTER(vbe->vmib.WinASegment, 0)))) + offset - vbe->windowA_offset; + +set_windowB: + winnum = offset / (vbe->vmib.WinGranularity * 1024); + code = VbeReallySetWindow(vi, 1, winnum); + if(code < 0) { + ErrorF("Couldn't set window B to %d*%d\n", + (int)winnum, (int)vbe->vmib.WinGranularity); + return NULL; + } + vbe->windowB_offset = winnum * vbe->vmib.WinGranularity * 1024; +windowB: + vbe->last_window = 1; + *size_return = vbe->vmib.WinSize * 1024 - (offset - vbe->windowB_offset); + return ((U8*)&(LM(vi, MAKE_POINTER(vbe->vmib.WinBSegment, 0)))) + offset - vbe->windowB_offset; +} + +static const int VbeDPMSModes[4] = { + 0x00, /* KD_DPMS_NORMAL */ + 0x01, /* KD_DPMS_STANDBY */ + 0x02, /* KD_DPMS_SUSPEND */ + 0x04, /* KD_DPMS_POWERDOWN */ +}; + +Bool +VbeDPMS(Vm86InfoPtr vi, int mode) +{ + int code; + + /* + * Check which modes are supported + */ + vi->vms.regs.eax = 0x4f10; + vi->vms.regs.ebx = 0x0000; + vi->vms.regs.es = 0; + vi->vms.regs.edi = 0; + code = VbeDoInterrupt10 (vi); + if (code < 0) + { + ErrorF ("No DPMS Support %d\n", code); + return FALSE; + } + /* Skip this stage if it's not supported */ + if (((vi->vms.regs.ebx >> 4) & VbeDPMSModes[mode]) != VbeDPMSModes[mode]) + return FALSE; + + /* Select this mode */ + vi->vms.regs.eax = 0x4f10; + vi->vms.regs.ebx = (VbeDPMSModes[mode] << 8) | 0x01; + code = VbeDoInterrupt10 (vi); + if (code < 0) + { + ErrorF ("DPMS failed %d\n", code); + return FALSE; + } + + return TRUE; +} + +Bool +VbeBoot(Vm86InfoPtr vi) +{ + int code; + int bus = 1; + int device = 0; + int function = 0; + + vi->vms.regs.eax = (bus << 8) | (device << 3) | (function & 0x7); + code = VbeDoInterruptE6 (vi); + ErrorF ("Boot: %d\n", code); + return TRUE; +} + +int +VbeDoInterrupt10(Vm86InfoPtr vi) +{ + int code; + int oldax; + + oldax = vi->vms.regs.eax & 0xFFFF; + + code = Vm86DoInterrupt(vi, 0x10); + if(code < 0) + return -1; + + 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) { + switch((vi->vms.regs.eax & 0xFF00)>>8) { + case 0: + ErrorF(" (success)\n"); + return 0; + case 1: + ErrorF(" (function call failed)\n"); + break; + case 2: + ErrorF(" (function not supported on this hardware)\n"); + break; + case 3: + ErrorF(" (function call invalid in this video mode)\n"); + break; + default: + ErrorF(" (unknown error)\n"); + break; + } return -1; + } else { + ErrorF("\n"); + } + } + return code; +} + +int +VbeDoInterruptE6(Vm86InfoPtr vi) +{ + int code; + int oldax; + + oldax = vi->vms.regs.eax & 0xffff; + + code = Vm86DoPOST (vi); + ErrorF("POST (0x%04X): 0x%04X\n", + oldax, vi->vms.regs.eax & 0xffff); + return code; +} |