You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1294 lines
30 KiB
1294 lines
30 KiB
//
|
|
// vga routines
|
|
//
|
|
|
|
#include "bldr.h"
|
|
#include "vga.h"
|
|
#include "cmdcnst.h"
|
|
|
|
PUCHAR VgaBase = (PUCHAR)0xa0000;
|
|
PUCHAR VgaRegisterBase = (PUCHAR)0;
|
|
|
|
//
|
|
// globals to track screen position
|
|
//
|
|
|
|
#define DELTA 80L
|
|
|
|
BOOLEAN
|
|
VgaInterpretCmdStream(
|
|
PUSHORT pusCmdStream
|
|
);
|
|
|
|
UCHAR lMaskTable[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
|
|
UCHAR rMaskTable[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
|
|
UCHAR PixelMask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
|
|
|
|
//
|
|
// Initialize AT registers
|
|
//
|
|
|
|
USHORT AT_Initialization[] = {
|
|
|
|
IB, // prepare atc for writing
|
|
INPUT_STATUS_1_COLOR,
|
|
|
|
METAOUT+ATCOUT, // program attribute controller registers
|
|
ATT_ADDRESS_PORT, // port
|
|
16, // count
|
|
0, // start index
|
|
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
|
|
|
|
IB, // prepare atc for writing
|
|
INPUT_STATUS_1_COLOR,
|
|
|
|
OB, // turn video on.
|
|
ATT_ADDRESS_PORT,
|
|
VIDEO_ENABLE,
|
|
|
|
EOD
|
|
|
|
};
|
|
|
|
ULONG lookup[16] =
|
|
{
|
|
0x00000000,
|
|
0x00000100,
|
|
0x00001000,
|
|
0x00001100,
|
|
0x00000001,
|
|
0x00000101,
|
|
0x00001001,
|
|
0x00001101,
|
|
0x00000010,
|
|
0x00000110,
|
|
0x00001010,
|
|
0x00001110,
|
|
0x00000011,
|
|
0x00000111,
|
|
0x00001011,
|
|
0x00001111
|
|
};
|
|
|
|
void __outpw(int p, int v)
|
|
{
|
|
WRITE_PORT_USHORT((PUSHORT)(p+VgaRegisterBase), (USHORT)v);
|
|
}
|
|
|
|
void __outpb(int p, int v)
|
|
{
|
|
WRITE_PORT_UCHAR((PUCHAR)(p+VgaRegisterBase), (UCHAR)v);
|
|
}
|
|
|
|
VOID
|
|
ReadWriteMode(
|
|
ULONG mode
|
|
)
|
|
{
|
|
UCHAR value;
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR)(VgaRegisterBase+0x3ce), 5);
|
|
value = READ_PORT_UCHAR((PUCHAR)(VgaRegisterBase+0x3cf));
|
|
|
|
value &= 0xf4;
|
|
value |= mode;
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR)(VgaRegisterBase+0x3cf), value);
|
|
}
|
|
|
|
VOID
|
|
SetPixel(
|
|
ULONG x,
|
|
ULONG y,
|
|
ULONG color
|
|
)
|
|
{
|
|
PUCHAR pDst;
|
|
ULONG bank;
|
|
|
|
bank = x >> 3;
|
|
|
|
pDst = (PUCHAR)(VgaBase + y * DELTA + bank);
|
|
|
|
ReadWriteMode(0x8 | 0x2);
|
|
__outpw(0x3c4, 0x0f02); // enable all write planes
|
|
__outpw(0x3ce, 0x0007); // set color don't care register to zero
|
|
__outpw(0x3ce, (PixelMask[x & 0x7] << 8) | 8);
|
|
|
|
WRITE_REGISTER_UCHAR(pDst, (UCHAR)(READ_REGISTER_UCHAR(pDst) & ((UCHAR)color)));
|
|
}
|
|
|
|
VOID
|
|
VidSolidColorFill(
|
|
ULONG x1,
|
|
ULONG y1,
|
|
ULONG x2,
|
|
ULONG y2,
|
|
ULONG color
|
|
)
|
|
{
|
|
PUCHAR pDst;
|
|
ULONG x, y;
|
|
ULONG bank1, bank2, count;
|
|
ULONG lMask, rMask;
|
|
|
|
lMask = (lMaskTable[x1 & 0x7] << 8) | 8;
|
|
rMask = (rMaskTable[x2 & 0x7] << 8) | 8;
|
|
|
|
bank1 = x1 >> 3;
|
|
bank2 = x2 >> 3;
|
|
count = bank2 - bank1;
|
|
|
|
if (!count) {
|
|
lMask = lMask & rMask;
|
|
}
|
|
|
|
ReadWriteMode(0x8 | 0x2);
|
|
|
|
__outpw(0x3c4, 0x0f02); // enable writing to all color planes
|
|
__outpw(0x3ce, 0x0007); // set color don't care register to zero
|
|
|
|
//
|
|
// Do the left edge
|
|
//
|
|
|
|
pDst = (PUCHAR)(VgaBase + y1 * DELTA + bank1);
|
|
|
|
__outpw(0x3ce, lMask);
|
|
|
|
for (y=y1; y<=y2; y++) {
|
|
|
|
WRITE_REGISTER_UCHAR(pDst, (UCHAR)(READ_REGISTER_UCHAR(pDst) & (UCHAR) color));
|
|
pDst += DELTA;
|
|
}
|
|
|
|
if (count) {
|
|
|
|
//
|
|
// Do the right edge
|
|
//
|
|
|
|
pDst = (PUCHAR)(VgaBase + y1 * DELTA + bank2);
|
|
count--;
|
|
__outpw(0x3ce, rMask);
|
|
|
|
for (y=y1; y<=y2; y++) {
|
|
WRITE_REGISTER_UCHAR(pDst, (UCHAR)(READ_REGISTER_UCHAR(pDst) & (UCHAR) color));
|
|
pDst += DELTA;
|
|
}
|
|
|
|
//
|
|
// Do the center section
|
|
//
|
|
|
|
if (count) {
|
|
|
|
pDst = (PUCHAR)(VgaBase + y1 * DELTA + bank1 + 1);
|
|
__outpw(0x3ce, 0xff08);
|
|
|
|
for (y=y1; y<=y2; y++) {
|
|
|
|
for (x=0; x<count; x++) {
|
|
WRITE_REGISTER_UCHAR(pDst++, (unsigned char) color);
|
|
}
|
|
pDst += DELTA - count;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
RleBitBlt(
|
|
ULONG x,
|
|
ULONG y,
|
|
ULONG width,
|
|
ULONG height,
|
|
PUCHAR Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine displays an RLE 4 bitmap.
|
|
|
|
Arguments:
|
|
|
|
x, y - location at which to display the bitmap.
|
|
|
|
width, height - height of the bitmap
|
|
|
|
Buffer - Pointer to the compressed bitmap data.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN Done = FALSE;
|
|
PUCHAR p = Buffer;
|
|
ULONG RunLength;
|
|
LONG RunExtra;
|
|
ULONG curr_x, curr_y;
|
|
ULONG Color1, Color2;
|
|
|
|
curr_x = x;
|
|
curr_y = y + height - 1;
|
|
|
|
while (!Done) {
|
|
|
|
if (*p) {
|
|
|
|
RunLength = (ULONG) *p++;
|
|
|
|
//
|
|
// Make sure we don't draw past end of scan.
|
|
//
|
|
|
|
if ((curr_x + RunLength) > (x + width))
|
|
RunLength -= (curr_x + RunLength) - (width + x);
|
|
|
|
Color1 = (*p & 0xf0) >> 4;
|
|
Color2 = (*p++ & 0x0f);
|
|
|
|
if (Color1 == Color2) {
|
|
|
|
ULONG end_x = curr_x + RunLength - 1;
|
|
|
|
VidSolidColorFill(curr_x,
|
|
curr_y,
|
|
end_x,
|
|
curr_y,
|
|
Color1);
|
|
|
|
curr_x += RunLength;
|
|
|
|
} else {
|
|
|
|
while (RunLength > 1) {
|
|
SetPixel(curr_x++, curr_y, Color1);
|
|
SetPixel(curr_x++, curr_y, Color2);
|
|
RunLength -= 2;
|
|
}
|
|
|
|
if (RunLength) {
|
|
SetPixel(curr_x, curr_y, Color1);
|
|
curr_x++;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
p++;
|
|
|
|
switch (*p) {
|
|
|
|
case 0: curr_x = x;
|
|
curr_y--;
|
|
p++;
|
|
break;
|
|
|
|
case 1: Done = TRUE;
|
|
p++;
|
|
break;
|
|
|
|
case 2: p++;
|
|
curr_x += (ULONG) *p++;
|
|
curr_y -= (ULONG) *p++;
|
|
break;
|
|
|
|
default: RunLength = (ULONG) *p++;
|
|
|
|
//
|
|
// Make sure we don't draw past end of scan.
|
|
//
|
|
|
|
if ((curr_x + RunLength) > (x + width)) {
|
|
RunExtra = (curr_x + RunLength) - (width + x);
|
|
RunLength -= RunExtra;
|
|
} else {
|
|
RunExtra = 0;
|
|
}
|
|
|
|
while (RunLength > 1) {
|
|
|
|
Color1 = (*p & 0xf0) >> 4;
|
|
Color2 = (*p++ & 0x0f);
|
|
|
|
SetPixel(curr_x++, curr_y, Color1);
|
|
SetPixel(curr_x++, curr_y, Color2);
|
|
|
|
RunLength -= 2;
|
|
}
|
|
|
|
if (RunLength) {
|
|
Color1 = (*p++ & 0xf0) >> 4;
|
|
SetPixel(curr_x++, curr_y, Color1);
|
|
RunExtra--;
|
|
}
|
|
|
|
//
|
|
// Read any remaining "extra" run data.
|
|
//
|
|
|
|
while (RunExtra > 0) {
|
|
p++;
|
|
RunExtra -= 2;
|
|
}
|
|
|
|
if ((ULONG_PTR)p & 1) p++; // make sure we are word aligned
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
BitBlt(
|
|
ULONG x,
|
|
ULONG y,
|
|
ULONG width,
|
|
ULONG height,
|
|
PUCHAR Buffer,
|
|
ULONG bpp,
|
|
LONG ScanWidth
|
|
)
|
|
{
|
|
ULONG i, j;
|
|
ULONG color=8;
|
|
|
|
if (bpp == 4) {
|
|
|
|
UCHAR Plane[81];
|
|
ULONG lMask, rMask, count;
|
|
ULONG bank1, bank2, bank;
|
|
ULONG bRightEdge = FALSE, bCenterSection = FALSE;
|
|
UCHAR value;
|
|
ULONG plane;
|
|
UCHAR Mask;
|
|
ULONG toggle;
|
|
PUCHAR pSrc, pSrcTemp;
|
|
PUCHAR pDst, pDstTemp;
|
|
UCHAR PlaneMask;
|
|
|
|
lMask = lMaskTable[x & 0x7];
|
|
rMask = rMaskTable[(x + width - 1) & 0x7];
|
|
|
|
bank1 = x >> 3;
|
|
bank2 = (x + width - 1) >> 3;
|
|
|
|
count = bank2 - bank1;
|
|
|
|
if (bank1 == bank2) {
|
|
|
|
lMask = lMask & rMask;
|
|
|
|
}
|
|
|
|
if (count) {
|
|
|
|
bRightEdge = TRUE;
|
|
|
|
count--;
|
|
|
|
if (count) {
|
|
|
|
bCenterSection = TRUE;
|
|
}
|
|
}
|
|
|
|
pDst = (PUCHAR)(VgaBase + (y * DELTA) + (x / 8));
|
|
pSrc = Buffer;
|
|
|
|
ReadWriteMode(0x0 | 0x0);
|
|
|
|
for (j=0; j<height; j++) {
|
|
|
|
for (plane=0; plane<4; plane++) {
|
|
|
|
pSrcTemp = pSrc;
|
|
pDstTemp = pDst;
|
|
|
|
PlaneMask = (UCHAR) (1 << plane);
|
|
|
|
//
|
|
// Convert the packed bitmap data into planar data
|
|
// for this plane.
|
|
//
|
|
// BUGBUG: My guess this is going to be a hot spot, so
|
|
// I need to revist this and optimize!! But for now
|
|
// make it work.
|
|
//
|
|
|
|
bank = bank1;
|
|
Plane[bank] = 0;
|
|
Mask = PixelMask[x & 0x7];
|
|
toggle = 0;
|
|
|
|
for (i=0; i<width; i++) {
|
|
|
|
if (toggle++ & 0x1) {
|
|
|
|
if (*pSrcTemp & PlaneMask) {
|
|
Plane[bank] |= Mask;
|
|
}
|
|
|
|
pSrcTemp++;
|
|
|
|
} else {
|
|
|
|
if (((*pSrcTemp) >> 4) & PlaneMask) {
|
|
Plane[bank] |= Mask;
|
|
}
|
|
}
|
|
|
|
Mask >>= 1;
|
|
|
|
if (!Mask) {
|
|
|
|
bank++;
|
|
Plane[bank] = 0;
|
|
Mask = 0x80;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set up the vga so that we see the correct bit plane.
|
|
//
|
|
|
|
__outpw(0x3c4, (1 << (plane + 8)) | 2);
|
|
|
|
//
|
|
// bank will go from bank1 to bank2
|
|
//
|
|
|
|
bank = bank1;
|
|
pDstTemp = pDst;
|
|
|
|
|
|
//
|
|
// Set Bitmask for left edge.
|
|
//
|
|
|
|
__outpw(0x3ce, (lMask << 8) | 8);
|
|
|
|
value = READ_REGISTER_UCHAR(pDstTemp);
|
|
|
|
value &= ~lMask;
|
|
value |= Plane[bank++];
|
|
|
|
WRITE_REGISTER_UCHAR(pDstTemp++, value);
|
|
|
|
if (bCenterSection) {
|
|
|
|
__outpw(0x3ce, 0xff08); // enable writing to all bits
|
|
|
|
for (i=0; i<count; i++) {
|
|
|
|
WRITE_REGISTER_UCHAR(pDstTemp++, Plane[bank++]);
|
|
}
|
|
}
|
|
|
|
if (bRightEdge) {
|
|
|
|
//
|
|
// Set bitmask for right edge.
|
|
//
|
|
|
|
__outpw(0x3ce, (rMask << 8) | 8);
|
|
|
|
value = READ_REGISTER_UCHAR(pDstTemp);
|
|
|
|
value &= ~rMask;
|
|
value |= Plane[bank];
|
|
|
|
WRITE_REGISTER_UCHAR(pDstTemp, value);
|
|
}
|
|
}
|
|
|
|
pDst += DELTA;
|
|
pSrc += ScanWidth;
|
|
}
|
|
|
|
} else {
|
|
|
|
PUCHAR pDst, pDstTemp;
|
|
PUCHAR pSrc, pSrcTemp;
|
|
ULONG count;
|
|
UCHAR Value;
|
|
ULONG lMask, rMask;
|
|
ULONG bank1, bank2;
|
|
ULONG plane;
|
|
UCHAR colorMask;
|
|
|
|
bank1 = x >> 8;
|
|
bank2 = (x + width - 1) >> 8;
|
|
|
|
lMask = lMaskTable[x & 7];
|
|
rMask = rMaskTable[(x + width - 1) & 7];
|
|
|
|
if (bank1 == bank2) {
|
|
|
|
lMask &= rMask;
|
|
}
|
|
|
|
lMask = ~lMask;
|
|
rMask = ~rMask;
|
|
|
|
pSrc = Buffer;
|
|
pDst = (PUCHAR)(VgaBase + (y * DELTA) + (x / 8));
|
|
|
|
ReadWriteMode(0x0 | 0x0);
|
|
|
|
for (j=0; j<height; j++) {
|
|
|
|
plane = 1;
|
|
for (i=0; i<4; i++) {
|
|
|
|
pDstTemp = pDst;
|
|
pSrcTemp = pSrc;
|
|
|
|
__outpw(0x3c4, (plane << 8) | 2);
|
|
|
|
colorMask = (UCHAR)((color & plane) ? 0xff : 0x00);
|
|
|
|
plane <<= 1; // bump up each time through loop
|
|
|
|
count = width;
|
|
|
|
//
|
|
// non aligned case
|
|
//
|
|
|
|
if (x & 7) {
|
|
|
|
//
|
|
// Left Edge.
|
|
//
|
|
|
|
Value = READ_REGISTER_UCHAR(pDstTemp);
|
|
|
|
Value &= lMask;
|
|
Value |= (*pSrcTemp >> x) & colorMask;
|
|
|
|
WRITE_REGISTER_UCHAR(pDstTemp++, Value);
|
|
|
|
count -= (8 - x);
|
|
|
|
//
|
|
// Now do center section
|
|
//
|
|
|
|
while (count > 7) {
|
|
|
|
Value = (UCHAR) ((*pSrcTemp << (8 - x)) | (*(pSrcTemp+1) >> x));
|
|
Value &= colorMask;
|
|
|
|
WRITE_REGISTER_UCHAR(pDstTemp++, Value);
|
|
|
|
pSrcTemp++;
|
|
count -= 8;
|
|
}
|
|
|
|
//
|
|
// Now do the right edge.
|
|
//
|
|
|
|
if (count) {
|
|
|
|
Value = READ_REGISTER_UCHAR(pDstTemp);
|
|
|
|
Value &= rMask;
|
|
Value |= *pSrcTemp << (8 - x) & colorMask;
|
|
|
|
WRITE_REGISTER_UCHAR(pDstTemp++, Value);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Aligned case.
|
|
//
|
|
|
|
ULONG ulColorMask = colorMask ? 0xffffffff : 0x00000000;
|
|
USHORT usColorMask = colorMask ? 0xffff : 0x0000;
|
|
|
|
while (count > 31) {
|
|
|
|
WRITE_REGISTER_ULONG((PULONG)pDstTemp, (ULONG)(*((PULONG)pSrcTemp) & ulColorMask));
|
|
count -= 32;
|
|
pDstTemp += sizeof(ULONG)/sizeof(UCHAR);
|
|
pSrcTemp += sizeof(ULONG)/sizeof(UCHAR);
|
|
}
|
|
|
|
while (count > 15) {
|
|
|
|
WRITE_REGISTER_USHORT((PUSHORT)pDstTemp, (USHORT)(*((PUSHORT)pSrcTemp) & usColorMask));
|
|
count -= 16;
|
|
pDstTemp += sizeof(USHORT)/sizeof(UCHAR);
|
|
pSrcTemp += sizeof(USHORT)/sizeof(UCHAR);
|
|
}
|
|
|
|
if (count > 7) {
|
|
|
|
WRITE_REGISTER_UCHAR(pDstTemp++, (UCHAR)(*pSrcTemp++ & colorMask));
|
|
count -= 8;
|
|
}
|
|
|
|
//
|
|
// Now do any remaining bits.
|
|
//
|
|
|
|
if (count) {
|
|
|
|
Value = READ_REGISTER_UCHAR(pDstTemp);
|
|
|
|
Value &= rMask;
|
|
Value |= *pSrcTemp & colorMask;
|
|
|
|
WRITE_REGISTER_UCHAR(pDstTemp++, Value);
|
|
}
|
|
}
|
|
}
|
|
|
|
pSrc += ScanWidth;
|
|
pDst += DELTA;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
VidBitBlt(
|
|
PUCHAR Buffer,
|
|
ULONG x,
|
|
ULONG y
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes a bitmap resource and displays it at a given
|
|
location.
|
|
|
|
Arguments:
|
|
|
|
Buffer - Pointer to the bitmap resource.
|
|
|
|
x, y - The position at which to display the bitmap.
|
|
|
|
--*/
|
|
|
|
{
|
|
PBITMAPINFOHEADER bih;
|
|
PRGBQUAD Palette;
|
|
|
|
LONG lDelta;
|
|
PUCHAR pBuffer;
|
|
LONG cbScanLine;
|
|
|
|
bih = (PBITMAPINFOHEADER) Buffer;
|
|
|
|
Palette = (PRGBQUAD)(((PUCHAR)bih) + bih->biSize);
|
|
|
|
//
|
|
// BUGBUG: I need to add some bitmap validation code here!
|
|
//
|
|
|
|
cbScanLine = (((bih->biWidth * bih->biBitCount) + 31) & ~31) >> 3;
|
|
|
|
pBuffer = (PUCHAR)(Buffer + sizeof(BITMAPINFOHEADER) + 64);
|
|
|
|
if (bih->biCompression == BI_RLE4) {
|
|
|
|
if (bih->biWidth && bih->biHeight) {
|
|
RleBitBlt(x,
|
|
y,
|
|
bih->biWidth,
|
|
bih->biHeight,
|
|
pBuffer);
|
|
}
|
|
|
|
} else {
|
|
|
|
if (bih->biHeight < 0) {
|
|
|
|
// top down bitmap
|
|
lDelta = cbScanLine;
|
|
bih->biHeight = -bih->biHeight;
|
|
|
|
} else {
|
|
|
|
// bottom up bitmap
|
|
pBuffer += cbScanLine * (bih->biHeight - 1);
|
|
lDelta = -cbScanLine;
|
|
}
|
|
|
|
if (bih->biWidth && bih->biHeight) {
|
|
BitBlt(x,
|
|
y,
|
|
bih->biWidth,
|
|
bih->biHeight,
|
|
pBuffer,
|
|
bih->biBitCount,
|
|
lDelta);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
VidScreenToBufferBlt(
|
|
PUCHAR Buffer,
|
|
ULONG x,
|
|
ULONG y,
|
|
ULONG width,
|
|
ULONG height,
|
|
ULONG lDelta
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allows you to copy a portion of video memory into
|
|
system memory.
|
|
|
|
Arguments:
|
|
|
|
Buffer - Points to system memory where the video image should be copied.
|
|
|
|
x, y - X,Y coordinates in video memory of top-left portion of image.
|
|
|
|
width, height - width and height of the image in pixels.
|
|
|
|
lDelta - width of the buffer in bytes.
|
|
|
|
Notes:
|
|
|
|
Upon completion, the video memory image will be in system memory. Each
|
|
plane of the image are stored seperately, so the first scan line of
|
|
plane 0 will be followed by the first scan line of plane 1, etc. Then
|
|
the second scan of plane 0, plane 1, and so on.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Plane, i, j, BankStart, BankEnd;
|
|
PUCHAR pSrc, pSrcTemp, pDst;
|
|
PULONG pulDstTemp;
|
|
UCHAR Val1, Val2;
|
|
ULONG Shift1, Shift2;
|
|
UCHAR ucCombined;
|
|
ULONG ulCombined;
|
|
|
|
BankStart = x >> 3;
|
|
BankEnd = (x + width - 1) >> 3;
|
|
Shift1 = x & 7;
|
|
Shift2 = 8 - Shift1;
|
|
|
|
//
|
|
// Zero initialize the buffer so we can or in the bits later!
|
|
//
|
|
|
|
pDst = Buffer;
|
|
memset(pDst, 0, lDelta * height);
|
|
|
|
for (Plane=0; Plane<4; Plane++) {
|
|
|
|
pSrc = (PUCHAR)(VgaBase + (DELTA * y) + BankStart);
|
|
pDst = Buffer;
|
|
|
|
ReadWriteMode(0x0 | 0x0); // set read mode 0
|
|
__outpw(0x3ce, (Plane << 8) | 0x04); // read from given plane
|
|
|
|
for (j=0; j<height; j++) {
|
|
|
|
pSrcTemp = pSrc;
|
|
pulDstTemp = (PULONG)pDst;
|
|
|
|
Val1 = READ_REGISTER_UCHAR(pSrcTemp++);
|
|
|
|
for (i=BankStart; i<=BankEnd; i++) {
|
|
|
|
Val2 = READ_REGISTER_UCHAR(pSrcTemp++);
|
|
|
|
ucCombined = (UCHAR) ((Val1 << Shift1) | (Val2 >> Shift2));
|
|
ulCombined = ((lookup[(ucCombined & 0x0f) >> 0] << 16) |
|
|
lookup[(ucCombined & 0xf0) >> 4]) << Plane;
|
|
|
|
|
|
*pulDstTemp++ |= ulCombined;
|
|
|
|
Val1 = Val2;
|
|
}
|
|
|
|
pSrc += DELTA; // go to next video memory scan line
|
|
pDst += lDelta; // go to next scan for this plane in buffer
|
|
}
|
|
}
|
|
}
|
|
|
|
void VidBufferToScreenBlt(
|
|
PUCHAR Buffer,
|
|
ULONG x,
|
|
ULONG y,
|
|
ULONG width,
|
|
ULONG height,
|
|
ULONG lDelta
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allows you to copy a portion of video memory into
|
|
system memory.
|
|
|
|
Arguments:
|
|
|
|
Buffer - Points to system memory where the video image should be copied
|
|
from.
|
|
|
|
x, y - X,Y coordinates in video memory of top-left portion of image.
|
|
|
|
width, height - width and height of the image in pixels.
|
|
|
|
lDelta - width of the buffer in bytes.
|
|
|
|
Notes:
|
|
|
|
This routine will allow you to blt from a buffer filled by
|
|
VidScreenToBufferBlt.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (width && height) {
|
|
BitBlt(x,
|
|
y,
|
|
width,
|
|
height,
|
|
Buffer,
|
|
4,
|
|
lDelta);
|
|
}
|
|
}
|
|
|
|
|
|
#pragma optimize( "", off )
|
|
|
|
VOID
|
|
SetPaletteEntryRGB(
|
|
ULONG index,
|
|
RGBQUAD rgb
|
|
)
|
|
{
|
|
__outpb(0x3c8, index);
|
|
__outpb(0x3c9, rgb.rgbRed >> 2);
|
|
__outpb(0x3c9, rgb.rgbGreen >> 2);
|
|
__outpb(0x3c9, rgb.rgbBlue >> 2);
|
|
}
|
|
|
|
VOID
|
|
VgaEnableVideo()
|
|
{
|
|
VgaInterpretCmdStream (AT_Initialization);
|
|
}
|
|
|
|
VOID
|
|
InitPaletteConversionTable()
|
|
{
|
|
/*
|
|
UCHAR n;
|
|
|
|
READ_PORT_UCHAR((PUCHAR)(VgaRegisterBase+INPUT_STATUS_1_COLOR));
|
|
|
|
for (n=0; n<16; n++) { // Initializing table of active palette entries.
|
|
WRITE_PORT_UCHAR((PUCHAR)(VgaRegisterBase+ATT_ADDRESS_PORT), n);
|
|
WRITE_PORT_UCHAR((PUCHAR)(VgaRegisterBase+ATT_ADDRESS_PORT), n);
|
|
}
|
|
*/
|
|
VgaEnableVideo();
|
|
}
|
|
|
|
VOID
|
|
InitializePalette(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG Palette[] =
|
|
{
|
|
0x00000000,
|
|
0x00000020,
|
|
0x00002000,
|
|
0x00002020,
|
|
0x00200000,
|
|
0x00200020,
|
|
0x00202000,
|
|
0x00202020,
|
|
0x00303030,
|
|
0x0000003f,
|
|
0x00003f00,
|
|
0x00003f3f,
|
|
0x003f0000,
|
|
0x003f003f,
|
|
0x003f3f00,
|
|
0x003f3f3f,
|
|
};
|
|
ULONG i;
|
|
|
|
for (i=0; i<16; i++) {
|
|
PRGBQUAD p = (PRGBQUAD)(Palette+i);
|
|
SetPaletteEntryRGB(i, *p);
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
InitPaletteWithTable(
|
|
PRGBQUAD Palette,
|
|
ULONG count
|
|
)
|
|
{
|
|
UCHAR i;
|
|
InitPaletteConversionTable();
|
|
count = 16;
|
|
for (i=0; i<count; i++)
|
|
SetPaletteEntryRGB (i, *Palette++);
|
|
}
|
|
|
|
VOID
|
|
InitPaletteWithBlack(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG i;
|
|
// RGBQUAD black = {0x3f,0x3f,0x3f,0x3f};
|
|
RGBQUAD black = {0,0,0,0};
|
|
InitPaletteConversionTable();
|
|
//InitializePalette();
|
|
|
|
for (i=0; i<16; i++)
|
|
SetPaletteEntryRGB(i, black);
|
|
}
|
|
|
|
VOID
|
|
WaitForVsync(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wait for a v-sync
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Check to see if vsync's are being generated.
|
|
//
|
|
|
|
WRITE_PORT_UCHAR((VgaRegisterBase+0x3c4), 00);
|
|
|
|
if (READ_PORT_UCHAR(VgaRegisterBase+0x3c5) & 0x2) {
|
|
|
|
ULONG MaxDelay;
|
|
|
|
//
|
|
// Slight delay. Wait for one vsync.
|
|
//
|
|
|
|
MaxDelay = 100000;
|
|
while (((READ_PORT_UCHAR(VgaRegisterBase+0x3da) & 0x08) == 0x08) && MaxDelay--);
|
|
MaxDelay = 100000;
|
|
while (((READ_PORT_UCHAR(VgaRegisterBase+0x3da) & 0x08) == 0x00) && MaxDelay--);
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
VgaInterpretCmdStream(
|
|
PUSHORT pusCmdStream
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Interprets the appropriate command array to set up VGA registers for the
|
|
requested mode. Typically used to set the VGA into a particular mode by
|
|
programming all of the registers
|
|
|
|
Arguments:
|
|
|
|
pusCmdStream - array of commands to be interpreted.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation (can only fail on a bad command); TRUE for
|
|
success, FALSE for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG ulCmd;
|
|
ULONG_PTR ulPort;
|
|
UCHAR jValue;
|
|
USHORT usValue;
|
|
ULONG culCount;
|
|
ULONG ulIndex;
|
|
ULONG_PTR ulBase;
|
|
|
|
if (pusCmdStream == NULL) {
|
|
|
|
//KdPrint(("VgaInterpretCmdStream: pusCmdStream == NULL\n"));
|
|
return TRUE;
|
|
}
|
|
|
|
ulBase = (ULONG_PTR) VgaRegisterBase;
|
|
|
|
//
|
|
// Now set the adapter to the desired mode.
|
|
//
|
|
|
|
while ((ulCmd = *pusCmdStream++) != EOD) {
|
|
|
|
WaitForVsync();
|
|
|
|
//
|
|
// Determine major command type
|
|
//
|
|
|
|
switch (ulCmd & 0xF0) {
|
|
|
|
//
|
|
// Basic input/output command
|
|
//
|
|
|
|
case INOUT:
|
|
|
|
//
|
|
// Determine type of inout instruction
|
|
//
|
|
|
|
if (!(ulCmd & IO)) {
|
|
|
|
//
|
|
// Out instruction. Single or multiple outs?
|
|
//
|
|
|
|
if (!(ulCmd & MULTI)) {
|
|
|
|
//
|
|
// Single out. Byte or word out?
|
|
//
|
|
|
|
if (!(ulCmd & BW)) {
|
|
|
|
//
|
|
// Single byte out
|
|
//
|
|
|
|
ulPort = *pusCmdStream++;
|
|
jValue = (UCHAR) *pusCmdStream++;
|
|
WRITE_PORT_UCHAR((PUCHAR)(ulBase+ulPort),
|
|
jValue);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Single word out
|
|
//
|
|
|
|
ulPort = *pusCmdStream++;
|
|
usValue = *pusCmdStream++;
|
|
WRITE_PORT_USHORT((PUSHORT)(ulBase+ulPort),
|
|
usValue);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Output a string of values
|
|
// Byte or word outs?
|
|
//
|
|
|
|
if (!(ulCmd & BW)) {
|
|
|
|
//
|
|
// String byte outs. Do in a loop; can't use
|
|
// VideoPortWritePortBufferUchar because the data
|
|
// is in USHORT form
|
|
//
|
|
|
|
ulPort = ulBase + *pusCmdStream++;
|
|
culCount = *pusCmdStream++;
|
|
|
|
while (culCount--) {
|
|
jValue = (UCHAR) *pusCmdStream++;
|
|
WRITE_PORT_UCHAR((PUCHAR)ulPort,
|
|
jValue);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// String word outs
|
|
//
|
|
|
|
ulPort = *pusCmdStream++;
|
|
culCount = *pusCmdStream++;
|
|
WRITE_PORT_BUFFER_USHORT((PUSHORT)
|
|
(ulBase + ulPort), pusCmdStream, culCount);
|
|
pusCmdStream += culCount;
|
|
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
// In instruction
|
|
//
|
|
// Currently, string in instructions aren't supported; all
|
|
// in instructions are handled as single-byte ins
|
|
//
|
|
// Byte or word in?
|
|
//
|
|
|
|
if (!(ulCmd & BW)) {
|
|
//
|
|
// Single byte in
|
|
//
|
|
|
|
ulPort = *pusCmdStream++;
|
|
jValue = READ_PORT_UCHAR((PUCHAR)ulBase+ulPort);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Single word in
|
|
//
|
|
|
|
ulPort = *pusCmdStream++;
|
|
usValue = READ_PORT_USHORT((PUSHORT)
|
|
(ulBase+ulPort));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// Higher-level input/output commands
|
|
//
|
|
|
|
case METAOUT:
|
|
|
|
//
|
|
// Determine type of metaout command, based on minor
|
|
// command field
|
|
//
|
|
switch (ulCmd & 0x0F) {
|
|
|
|
//
|
|
// Indexed outs
|
|
//
|
|
|
|
case INDXOUT:
|
|
|
|
ulPort = ulBase + *pusCmdStream++;
|
|
culCount = *pusCmdStream++;
|
|
ulIndex = *pusCmdStream++;
|
|
|
|
while (culCount--) {
|
|
|
|
usValue = (USHORT) (ulIndex +
|
|
(((ULONG)(*pusCmdStream++)) << 8));
|
|
WRITE_PORT_USHORT((PUSHORT)ulPort, usValue);
|
|
|
|
ulIndex++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// Masked out (read, AND, XOR, write)
|
|
//
|
|
|
|
case MASKOUT:
|
|
|
|
ulPort = *pusCmdStream++;
|
|
jValue = READ_PORT_UCHAR((PUCHAR)ulBase+ulPort);
|
|
jValue &= *pusCmdStream++;
|
|
jValue ^= *pusCmdStream++;
|
|
WRITE_PORT_UCHAR((PUCHAR)ulBase + ulPort,
|
|
jValue);
|
|
break;
|
|
|
|
//
|
|
// Attribute Controller out
|
|
//
|
|
|
|
case ATCOUT:
|
|
|
|
ulPort = ulBase + *pusCmdStream++;
|
|
culCount = *pusCmdStream++;
|
|
ulIndex = *pusCmdStream++;
|
|
|
|
while (culCount--) {
|
|
|
|
// Write Attribute Controller index
|
|
WRITE_PORT_UCHAR((PUCHAR)ulPort,
|
|
(UCHAR)ulIndex);
|
|
|
|
// Write Attribute Controller data
|
|
jValue = (UCHAR) *pusCmdStream++;
|
|
WRITE_PORT_UCHAR((PUCHAR)ulPort, jValue);
|
|
|
|
ulIndex++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// None of the above; error
|
|
//
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
//
|
|
// NOP
|
|
//
|
|
|
|
case NCMD:
|
|
|
|
break;
|
|
|
|
//
|
|
// Unknown command; error
|
|
//
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
return TRUE;
|
|
|
|
} // end VgaInterpretCmdStream()
|
|
|