vga-logic-processor-examples/vesa.c

134 lines
2.6 KiB
C

#include <memory.h>
#include <i86.h>
#include <dos.h>
#include "dpmi.h"
#include "vesa.h"
char far *VGA = (char*)0xA0000;
long windowSizeBytes, bytesPerScanLine;
void *dosmem;
int currentWindowPosition;
#define MAX_COLORS (256)
void setupVESAHandling() {
dosmem = dpmiAllocateDOSMemory(1024);
}
void teardownVESAHandling() {
dpmiDeallocateDOSMemory();
}
void addDOSMemToRealModeRegs(struct dpmiRealModeRegs *rc) {
rc->edi = (unsigned long)dosmem & 0xf;
rc->es = (unsigned long)dosmem >> 4;
}
void vbeGetModeInfo(
uint16_t mode,
struct VbeModeInfo *modeInfo
) {
struct dpmiRealModeRegs rc={0};
_fmemset(dosmem, 0, sizeof(struct VbeModeInfo));
rc.eax = 0x4f01;
rc.ecx = mode;
addDOSMemToRealModeRegs(&rc);
dpmiInt(0x10, &rc);
_fmemcpy(modeInfo, dosmem, sizeof(struct VbeModeInfo));
}
int vbeGetVBEInfo(
struct VbeInfo far *p
) {
struct dpmiRealModeRegs rc={0};
// request VBE2 extended info
_fmemset(p, 0, sizeof(struct VbeInfo));
_fmemcpy(p->VbeSignature,"VBE2",4);
_fmemcpy(dosmem, p, sizeof(struct VbeInfo));
rc.eax = 0x4f00;
addDOSMemToRealModeRegs(&rc);
dpmiInt(0x10, &rc);
_fmemcpy(p, dosmem, sizeof(struct VbeInfo));
return 0;
}
void startSVGAMode(int mode, struct VbeModeInfo *vbeModeInfo) {
/**
* Side effects: sets some internal variables for window and scanline sizes
*/
union REGS regs;
vbeGetModeInfo(mode, vbeModeInfo);
windowSizeBytes = 1024L * vbeModeInfo->WinSize;
bytesPerScanLine = vbeModeInfo->BytesPerScanLine;
regs.w.ax = 0x4f02;
regs.w.bx = mode;
int386(0x10, &regs, &regs);
vbeSetWindow(0, 0);
}
void vbeSetWindow(int window, int position) {
/**
* Side effects: tracks current window position
*/
union REGS regs;
regs.w.ax = 0x4f05;
regs.h.bh = 0;
regs.h.bl = window;
regs.w.dx = position;
int386(0x10, &regs, &regs);
currentWindowPosition = position;
}
void maybeVbeSetWindow(int window, int position) {
if (currentWindowPosition == position) return;
vbeSetWindow(window, position);
}
void setVESAColorPalette(
struct VESAColor *colors
) {
struct dpmiRealModeRegs rc={0};
int i;
_fmemcpy(dosmem, colors, MAX_COLORS * 4);
// prep our real mode interrupt call
rc.eax = 0x4f09;
rc.ebx = 0;
rc.ecx = MAX_COLORS;
rc.edx = 0;
addDOSMemToRealModeRegs(&rc);
dpmiInt(0x10, &rc);
}
void setPixel(int x, int y, int color) {
long absolutePosition = (long)y * bytesPerScanLine + x;
long windowPosition = absolutePosition / windowSizeBytes;
long windowOffset = absolutePosition % windowSizeBytes;
/**
* This will not shift window positions unless needed.
*/
maybeVbeSetWindow(0, windowPosition);
VGA[windowOffset] = color;
}