2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: VGA hardware emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
19 /* PRIVATE VARIABLES **********************************************************/
21 static CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
22 static CONST DWORD MemoryLimit
[] = { 0xAFFFF, 0xAFFFF, 0xB7FFF, 0xBFFFF };
24 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
26 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
27 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
28 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
29 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
30 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
31 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
32 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
33 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
34 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
35 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
36 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
37 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
38 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
39 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
40 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
41 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
42 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
43 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
44 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
45 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
46 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
47 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
48 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
49 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
50 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
51 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
52 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
53 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
54 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
55 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
56 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
57 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
58 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
59 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
60 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
61 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
62 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
63 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
64 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
65 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
66 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
67 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
68 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
69 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
70 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
71 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
72 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
73 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
74 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
75 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
76 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
77 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
78 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
79 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
80 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
81 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
82 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
83 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
84 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
85 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
86 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
87 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
88 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
89 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
92 static BYTE VgaMemory
[VGA_NUM_BANKS
* VGA_BANK_SIZE
];
93 static LPVOID ConsoleFramebuffer
= NULL
;
94 static HANDLE TextConsoleBuffer
= NULL
;
95 static HANDLE GraphicsConsoleBuffer
= NULL
;
96 static HANDLE ConsoleMutex
= NULL
;
97 static HPALETTE PaletteHandle
= NULL
;
98 static BOOLEAN DoubleVision
= FALSE
;
100 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
101 static BYTE VgaMiscRegister
;
103 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
104 static BYTE VgaSeqRegisters
[VGA_SEQ_MAX_REG
];
106 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
107 static BYTE VgaGcRegisters
[VGA_GC_MAX_REG
];
109 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
110 static BYTE VgaCrtcRegisters
[VGA_CRTC_MAX_REG
];
112 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
113 static BOOLEAN VgaAcLatch
= FALSE
;
114 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
116 static WORD VgaDacIndex
= 0;
117 static BOOLEAN VgaDacReadWrite
= FALSE
;
118 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
120 static BOOLEAN InVerticalRetrace
= FALSE
;
121 static BOOLEAN InHorizontalRetrace
= FALSE
;
123 static BOOLEAN NeedsUpdate
= FALSE
;
124 static BOOLEAN ModeChanged
= TRUE
;
125 static BOOLEAN CursorMoved
= FALSE
;
126 static BOOLEAN PaletteChanged
= FALSE
;
127 static BOOLEAN TextMode
= TRUE
;
129 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
131 /* PRIVATE FUNCTIONS **********************************************************/
133 static inline INT
VgaGetAddressSize(VOID
)
135 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
137 /* Double-word addressing */
138 return 4; // sizeof(DWORD)
141 if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
143 /* Byte addressing */
144 return 1; // sizeof(BYTE)
147 /* Word addressing */
148 return 2; // sizeof(WORD)
151 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
153 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
156 /* Check for chain-4 and odd-even mode */
157 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
159 /* The lowest two bits are the plane number */
163 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
165 /* The LSB is the plane number */
171 /* Use the read mode */
172 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
175 /* Multiply the offset by the address size */
176 Offset
*= VgaGetAddressSize();
178 return Offset
+ Plane
* VGA_BANK_SIZE
;
181 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
183 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
185 /* Check for chain-4 and odd-even mode */
186 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
188 /* Shift the offset to the right by 2 */
191 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
193 /* Shift the offset to the right by 1 */
197 /* Multiply the offset by the address size */
198 Offset
*= VgaGetAddressSize();
200 /* Return the offset on plane 0 */
204 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
206 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 3;
207 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 3;
208 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 7;
209 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
213 /* In write mode 1 just return the latch register */
214 return VgaLatchRegisters
[Plane
];
219 /* Write modes 0 and 3 rotate the data to the right first */
220 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
224 /* Write mode 2 expands the appropriate bit to all 8 bits */
225 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
231 * In write mode 0, the enable set/reset register decides if the
232 * set/reset bit should be expanded to all 8 bits.
234 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
236 /* Copy the bit from the set/reset register to all 8 bits */
237 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
243 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
244 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
245 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
246 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
250 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
253 /* Then we expand the bit in the set/reset field */
254 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
257 /* Bits cleared in the bitmask are replaced with latch register bits */
258 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
260 /* Return the byte */
264 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
266 DPRINT("VgaMarkForUpdate: Row %d, Column %d\n", Row
, Column
);
268 /* Check if this is the first time the rectangle is updated */
271 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
272 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
275 /* Expand the rectangle to include the point */
276 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
277 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
278 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
279 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
281 /* Set the update request flag */
285 static VOID
VgaWriteSequencer(BYTE Data
)
287 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
290 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
293 static VOID
VgaWriteGc(BYTE Data
)
295 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
298 VgaGcRegisters
[VgaGcIndex
] = Data
;
300 /* Check the index */
303 case VGA_GC_MISC_REG
:
305 /* The GC misc register decides if it's text or graphics mode */
313 static VOID
VgaWriteCrtc(BYTE Data
)
315 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
318 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
320 /* Check the index */
321 switch (VgaCrtcIndex
)
323 case VGA_CRTC_END_HORZ_DISP_REG
:
324 case VGA_CRTC_VERT_DISP_END_REG
:
325 case VGA_CRTC_OVERFLOW_REG
:
327 /* The video mode has changed */
333 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
334 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
335 case VGA_CRTC_CURSOR_START_REG
:
336 case VGA_CRTC_CURSOR_END_REG
:
338 /* Set the cursor moved flag */
346 static VOID
VgaWriteDac(BYTE Data
)
352 VgaDacRegisters
[VgaDacIndex
] = Data
;
354 /* Find the palette index */
355 PaletteIndex
= VgaDacIndex
/ 3;
357 /* Fill the entry structure */
358 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3]);
359 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 1]);
360 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 2]);
363 /* Update the palette entry */
364 SetPaletteEntries(PaletteHandle
, PaletteIndex
, 1, &Entry
);
366 /* Set the palette change flag */
367 PaletteChanged
= TRUE
;
369 /* Update the index */
371 VgaDacIndex
%= VGA_PALETTE_SIZE
;
374 static VOID
VgaWriteAc(BYTE Data
)
376 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
379 VgaAcRegisters
[VgaAcIndex
] = Data
;
381 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
383 /* Set the palette change flag */
384 PaletteChanged
= TRUE
;
388 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
392 /* Copy the colors of the default palette to the DAC and console palette */
393 for (i
= 0; i
< NumOfEntries
; i
++)
395 /* Set the palette entries */
396 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
397 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
398 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
399 Entries
[i
].peFlags
= 0;
401 /* Set the DAC registers */
402 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
403 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
404 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
408 static BOOLEAN
VgaInitializePalette(VOID
)
410 LPLOGPALETTE Palette
;
412 /* Allocate storage space for the palette */
413 Palette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
416 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
417 if (Palette
== NULL
) return FALSE
;
419 /* Initialize the palette */
420 Palette
->palVersion
= 0x0300;
421 Palette
->palNumEntries
= VGA_MAX_COLORS
;
423 /* Restore the default palette */
424 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
426 /* Create the palette */
427 PaletteHandle
= CreatePalette(Palette
);
429 /* Free the palette */
430 HeapFree(GetProcessHeap(), 0, Palette
);
432 /* Fail if the palette wasn't successfully created... */
433 if (PaletteHandle
== NULL
) return FALSE
;
435 /* ... otherwise return success */
439 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
442 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
443 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
444 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
445 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
447 if ((Resolution
->X
< VGA_MINIMUM_WIDTH
) && (Resolution
->Y
< VGA_MINIMUM_HEIGHT
))
454 /* Fill the bitmap info header */
455 ZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BITMAPINFOHEADER
));
456 BitmapInfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
457 BitmapInfo
->bmiHeader
.biWidth
= Resolution
->X
;
458 BitmapInfo
->bmiHeader
.biHeight
= Resolution
->Y
;
459 BitmapInfo
->bmiHeader
.biBitCount
= 8;
460 BitmapInfo
->bmiHeader
.biPlanes
= 1;
461 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
462 BitmapInfo
->bmiHeader
.biSizeImage
= Resolution
->X
* Resolution
->Y
/* * 1 == biBitCount / 8 */;
464 /* Fill the palette data */
465 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
467 /* Fill the console graphics buffer info */
468 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
469 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
470 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
472 /* Create the buffer */
473 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
474 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
476 CONSOLE_GRAPHICS_BUFFER
,
477 &GraphicsBufferInfo
);
478 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
480 /* Save the framebuffer address and mutex */
481 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
482 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
484 /* Clear the framebuffer */
485 ZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
487 /* Set the active buffer */
488 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer
);
490 /* Set the graphics mode palette */
491 SetConsolePalette(GraphicsConsoleBuffer
,
495 /* Clear the text mode flag */
501 static VOID
VgaLeaveGraphicsMode(VOID
)
503 /* Release the console framebuffer mutex if needed */
504 ReleaseMutex(ConsoleMutex
);
506 /* Switch back to the text buffer */
507 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
509 /* Cleanup the video data */
510 CloseHandle(ConsoleMutex
);
512 CloseHandle(GraphicsConsoleBuffer
);
513 GraphicsConsoleBuffer
= NULL
;
514 DoubleVision
= FALSE
;
517 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
519 /* Resize the console */
520 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
522 /* Allocate a framebuffer */
523 ConsoleFramebuffer
= HeapAlloc(GetProcessHeap(),
525 Resolution
->X
* Resolution
->Y
526 * sizeof(CHAR_INFO
));
527 if (ConsoleFramebuffer
== NULL
)
529 DisplayMessage(L
"An unexpected error occurred!\n");
535 * Set the text mode palette.
537 * WARNING: This call should fail on Windows (and therefore
538 * we get the default palette and our external behaviour is
539 * just like Windows' one), but it should success on ReactOS
540 * (so that we get console palette changes even for text-mode
541 * screen-buffers, which is a new feature on ReactOS).
543 SetConsolePalette(TextConsoleBuffer
,
547 /* Set the text mode flag */
553 static VOID
VgaLeaveTextMode(VOID
)
555 /* Free the old framebuffer */
556 HeapFree(GetProcessHeap(), 0, ConsoleFramebuffer
);
557 ConsoleFramebuffer
= NULL
;
560 static VOID
VgaChangeMode(VOID
)
562 COORD Resolution
= VgaGetDisplayResolution();
564 /* Reset the mode change flag */
565 // ModeChanged = FALSE;
569 /* Leave the current graphics mode */
570 VgaLeaveGraphicsMode();
574 /* Leave the current text mode */
578 /* Check if the new mode is alphanumeric */
579 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
))
581 /* Enter new text mode */
582 if (!VgaEnterTextMode(&Resolution
))
584 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode.");
591 /* Enter 8-bit graphics mode */
592 if (!VgaEnterGraphicsMode(&Resolution
))
594 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode.");
600 /* Trigger a full update of the screen */
602 UpdateRectangle
.Left
= 0;
603 UpdateRectangle
.Top
= 0;
604 UpdateRectangle
.Right
= Resolution
.X
;
605 UpdateRectangle
.Bottom
= Resolution
.Y
;
607 /* Reset the mode change flag */
611 static VOID
VgaUpdateFramebuffer(VOID
)
614 COORD Resolution
= VgaGetDisplayResolution();
615 INT AddressSize
= VgaGetAddressSize();
616 DWORD Address
= (VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
] << 8)
617 + VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
];
618 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
621 * If console framebuffer is NULL, that means something went wrong
622 * earlier and this is the final display refresh.
624 if (ConsoleFramebuffer
== NULL
) return;
626 /* Check if this is text mode or graphics mode */
627 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
630 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
633 * Synchronize access to the graphics framebuffer
634 * with the console framebuffer mutex.
636 WaitForSingleObject(ConsoleMutex
, INFINITE
);
638 /* Loop through the scanlines */
639 for (i
= 0; i
< Resolution
.Y
; i
++)
641 /* Loop through the pixels */
642 for (j
= 0; j
< Resolution
.X
; j
++)
646 /* Check the shifting mode */
647 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
649 /* 4 bits shifted from each plane */
651 /* Check if this is 16 or 256 color mode */
652 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
654 /* One byte per pixel */
655 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
656 + (Address
+ (j
/ VGA_NUM_BANKS
))
661 /* 4-bits per pixel */
663 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
664 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
667 /* Check if we should use the highest 4 bits or lowest 4 */
668 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
680 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
682 /* Check if this is 16 or 256 color mode */
683 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
685 // TODO: NOT IMPLEMENTED
686 DPRINT1("8-bit interleaved mode is not implemented!\n");
691 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
692 * then 2 bits shifted from plane 1 and 3 for the next 4
694 BYTE LowPlaneData
= VgaMemory
[((j
/ 4) % 2) * VGA_BANK_SIZE
695 + (Address
+ (j
/ 4)) * AddressSize
];
696 BYTE HighPlaneData
= VgaMemory
[(((j
/ 4) % 2) + 2) * VGA_BANK_SIZE
697 + (Address
+ (j
/ 4)) * AddressSize
];
699 /* Extract the two bits from each plane */
700 LowPlaneData
= (LowPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
701 HighPlaneData
= (HighPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
703 /* Combine them into the pixel */
704 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
709 /* 1 bit shifted from each plane */
711 /* Check if this is 16 or 256 color mode */
712 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
714 /* 8 bits per pixel, 2 on each plane */
716 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
718 /* The data is on plane k, 4 pixels per byte */
719 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
720 + (Address
+ (j
/ 4)) * AddressSize
];
722 /* The mask of the first bit in the pair */
723 BYTE BitMask
= 1 << (((3 - (j
% 4)) * 2) + 1);
725 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
726 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
728 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
729 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
734 /* 4 bits per pixel, 1 on each plane */
736 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
738 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
739 + (Address
+ (j
/ 8)) * AddressSize
];
741 /* If the bit on that plane is set, set it */
742 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
747 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
749 /* In 16 color mode, the value is an index to the AC registers */
750 PixelData
= VgaAcRegisters
[PixelData
];
755 /* Now check if the resulting pixel data has changed */
756 if (GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] != PixelData
)
758 /* Yes, write the new value */
759 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] = PixelData
;
760 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2 + 1)] = PixelData
;
761 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2)] = PixelData
;
762 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
764 /* Mark the specified pixel as changed */
765 VgaMarkForUpdate(i
, j
);
770 /* Now check if the resulting pixel data has changed */
771 if (GraphicsBuffer
[i
* Resolution
.X
+ j
] != PixelData
)
773 /* Yes, write the new value */
774 GraphicsBuffer
[i
* Resolution
.X
+ j
] = PixelData
;
776 /* Mark the specified pixel as changed */
777 VgaMarkForUpdate(i
, j
);
782 /* Move to the next scanline */
783 Address
+= ScanlineSize
;
787 * Release the console framebuffer mutex
788 * so that we allow for repainting.
790 ReleaseMutex(ConsoleMutex
);
795 PCHAR_INFO CharBuffer
= (PCHAR_INFO
)ConsoleFramebuffer
;
797 /* Loop through the scanlines */
798 for (i
= 0; i
< Resolution
.Y
; i
++)
800 /* Loop through the characters */
801 for (j
= 0; j
< Resolution
.X
; j
++)
803 DWORD CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
806 /* Plane 0 holds the character itself */
807 CharInfo
.Char
.AsciiChar
= VgaMemory
[CurrentAddr
];
809 /* Plane 1 holds the attribute */
810 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
812 /* Now check if the resulting character data has changed */
813 if ((CharBuffer
[i
* Resolution
.X
+ j
].Char
.AsciiChar
!= CharInfo
.Char
.AsciiChar
)
814 || (CharBuffer
[i
* Resolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
816 /* Yes, write the new value */
817 CharBuffer
[i
* Resolution
.X
+ j
] = CharInfo
;
819 /* Mark the specified cell as changed */
820 VgaMarkForUpdate(i
, j
);
824 /* Move to the next scanline */
825 Address
+= ScanlineSize
;
830 static VOID
VgaUpdateTextCursor(VOID
)
833 CONSOLE_CURSOR_INFO CursorInfo
;
834 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x3F;
835 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
836 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
837 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
838 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
839 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
841 if (CursorStart
< CursorEnd
)
844 CursorInfo
.bVisible
= TRUE
;
845 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
850 CursorInfo
.bVisible
= FALSE
;
851 CursorInfo
.dwSize
= 0;
854 /* Add the cursor skew to the location */
855 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 3;
857 /* Find the coordinates of the new position */
858 Position
.X
= (WORD
)(Location
% ScanlineSize
);
859 Position
.Y
= (WORD
)(Location
/ ScanlineSize
);
861 /* Update the physical cursor */
862 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
863 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
865 /* Reset the cursor move flag */
869 /* PUBLIC FUNCTIONS ***********************************************************/
871 DWORD
VgaGetVideoBaseAddress(VOID
)
873 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
876 DWORD
VgaGetVideoLimitAddress(VOID
)
878 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
881 COORD
VgaGetDisplayResolution(VOID
)
884 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
886 /* The low 8 bits are in the display registers */
887 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
888 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
890 /* Set the top bits from the overflow register */
891 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
893 Resolution
.Y
|= 1 << 8;
895 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
897 Resolution
.Y
|= 1 << 9;
900 /* Increase the values by 1 */
904 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
906 /* Multiply the horizontal resolution by the 9/8 dot mode */
907 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
910 /* The horizontal resolution is halved in 8-bit mode */
911 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
914 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
916 /* Halve the vertical resolution */
920 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
921 Resolution
.Y
/= MaximumScanLine
;
923 /* Return the resolution */
927 VOID
VgaRefreshDisplay(VOID
)
929 HANDLE ConsoleBufferHandle
= NULL
;
930 COORD Resolution
= VgaGetDisplayResolution();
932 DPRINT("VgaRefreshDisplay\n");
934 /* Change the display mode */
935 if (ModeChanged
) VgaChangeMode();
937 /* Change the text cursor location */
938 if (CursorMoved
) VgaUpdateTextCursor();
942 /* Trigger a full update of the screen */
944 UpdateRectangle
.Left
= 0;
945 UpdateRectangle
.Top
= 0;
946 UpdateRectangle
.Right
= Resolution
.X
;
947 UpdateRectangle
.Bottom
= Resolution
.Y
;
949 PaletteChanged
= FALSE
;
952 /* Update the contents of the framebuffer */
953 VgaUpdateFramebuffer();
955 /* Set the vertical retrace flag */
956 InVerticalRetrace
= TRUE
;
958 /* Ignore if there's nothing to update */
959 if (!NeedsUpdate
) return;
961 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
962 UpdateRectangle
.Left
,
964 UpdateRectangle
.Right
,
965 UpdateRectangle
.Bottom
);
967 /* Check if this is text mode or graphics mode */
968 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
971 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
976 COORD Origin
= { UpdateRectangle
.Left
, UpdateRectangle
.Top
};
977 ConsoleBufferHandle
= TextConsoleBuffer
;
979 /* Write the data to the console */
980 WriteConsoleOutputA(TextConsoleBuffer
,
981 (PCHAR_INFO
)ConsoleFramebuffer
,
989 /* Scale the update rectangle */
990 UpdateRectangle
.Left
*= 2;
991 UpdateRectangle
.Top
*= 2;
992 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
993 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
996 /* Redraw the screen */
997 InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
999 /* Clear the update flag */
1000 NeedsUpdate
= FALSE
;
1003 VOID
VgaHorizontalRetrace(VOID
)
1006 InHorizontalRetrace
= TRUE
;
1009 VOID
VgaReadMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1014 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n",
1018 /* Ignore if video RAM access is disabled */
1019 if (!(VgaMiscRegister
& VGA_MISC_RAM_ENABLED
)) return;
1021 /* Loop through each byte */
1022 for (i
= 0; i
< Size
; i
++)
1024 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1026 /* Load the latch registers */
1027 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1028 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1029 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1030 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1032 /* Copy the value to the buffer */
1033 Buffer
[i
] = VgaMemory
[VideoAddress
];
1037 VOID
VgaWriteMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1042 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n",
1046 /* Ignore if video RAM access is disabled */
1047 if (!(VgaMiscRegister
& VGA_MISC_RAM_ENABLED
)) return;
1049 /* Also ignore if write access to all planes is disabled */
1050 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return;
1052 /* Loop through each byte */
1053 for (i
= 0; i
< Size
; i
++)
1055 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1057 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1059 /* Make sure the page is writeable */
1060 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1062 /* Check if this is chain-4 mode */
1063 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1065 if (((Address
+ i
) & 3) != j
)
1067 /* This plane will not be accessed */
1072 /* Check if this is odd-even mode */
1073 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1075 if (((Address
+ i
) & 1) != (j
& 1))
1077 /* This plane will not be accessed */
1082 /* Copy the value to the VGA memory */
1083 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(Buffer
[i
], j
);
1088 BYTE WINAPI
VgaReadPort(ULONG Port
)
1090 DPRINT("VgaReadPort: Port 0x%08X\n", Port
);
1101 return VgaAcRegisters
[VgaAcIndex
];
1111 return VgaSeqRegisters
[VgaSeqIndex
];
1114 case VGA_DAC_READ_INDEX
:
1116 /* This returns the read/write state */
1117 return VgaDacReadWrite
? 0 : 3;
1120 case VGA_DAC_WRITE_INDEX
:
1122 return VgaDacIndex
/ 3;
1127 /* Ignore reads in write mode */
1128 if (!VgaDacReadWrite
)
1130 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
1131 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1140 return VgaMiscRegister
;
1143 case VGA_CRTC_INDEX
:
1145 return VgaCrtcIndex
;
1150 return VgaCrtcRegisters
[VgaCrtcIndex
];
1160 return VgaGcRegisters
[VgaGcIndex
];
1164 case VGA_STAT_COLOR
:
1168 /* Reset the AC latch */
1171 /* Set a flag if there is a vertical or horizontal retrace */
1172 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
1174 /* Set an additional flag if there was a vertical retrace */
1175 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
1177 /* Clear the flags */
1178 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
1187 VOID WINAPI
VgaWritePort(ULONG Port
, BYTE Data
)
1189 DPRINT("VgaWritePort: Port 0x%08X, Data 0x%02X\n", Port
, Data
);
1197 /* Change the index */
1198 if (Data
< VGA_AC_MAX_REG
) VgaAcIndex
= Data
;
1202 /* Write the data */
1206 /* Toggle the latch */
1207 VgaAcLatch
= !VgaAcLatch
;
1214 /* Set the sequencer index register */
1215 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
1221 /* Call the sequencer function */
1222 VgaWriteSequencer(Data
);
1226 case VGA_DAC_READ_INDEX
:
1228 VgaDacReadWrite
= FALSE
;
1229 VgaDacIndex
= Data
* 3;
1233 case VGA_DAC_WRITE_INDEX
:
1235 VgaDacReadWrite
= TRUE
;
1236 VgaDacIndex
= Data
* 3;
1242 /* Ignore writes in read mode */
1243 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1247 case VGA_MISC_WRITE
:
1249 VgaMiscRegister
= Data
;
1253 case VGA_CRTC_INDEX
:
1255 /* Set the CRTC index register */
1256 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
1262 /* Call the CRTC function */
1269 /* Set the GC index register */
1270 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
1276 /* Call the GC function */
1283 VOID
VgaClearMemory(VOID
)
1285 ZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1288 VOID
VgaResetPalette(VOID
)
1290 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
1292 /* Restore the default palette */
1293 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
1295 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
1296 PaletteChanged
= TRUE
;
1299 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
1305 COORD Origin
= { 0, 0 };
1306 SMALL_RECT ScreenRect
;
1307 PCHAR_INFO CharBuffer
;
1311 /* Initialize the VGA palette and fail if it isn't successfully created */
1312 if (!VgaInitializePalette()) return FALSE
;
1314 /* Set the global handle */
1315 TextConsoleBuffer
= TextHandle
;
1317 /* Clear the VGA memory */
1320 /* Set the default video mode */
1321 BiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE
);
1325 Resolution
= VgaGetDisplayResolution();
1326 CharBuffer
= (PCHAR_INFO
)ConsoleFramebuffer
;
1327 AddressSize
= VgaGetAddressSize();
1328 ScreenRect
.Left
= ScreenRect
.Top
= 0;
1329 ScreenRect
.Right
= Resolution
.X
;
1330 ScreenRect
.Bottom
= Resolution
.Y
;
1331 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1333 /* Read the data from the console into the framebuffer */
1334 ReadConsoleOutputA(TextConsoleBuffer
,
1340 /* Loop through the scanlines */
1341 for (i
= 0; i
< Resolution
.Y
; i
++)
1343 /* Loop through the characters */
1344 for (j
= 0; j
< Resolution
.X
; j
++)
1346 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1348 /* Store the character in plane 0 */
1349 VgaMemory
[CurrentAddr
] = CharBuffer
[i
* Resolution
.X
+ j
].Char
.AsciiChar
;
1351 /* Store the attribute in plane 1 */
1352 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuffer
[i
* Resolution
.X
+ j
].Attributes
;
1355 /* Move to the next scanline */
1356 Address
+= ScanlineSize
;
1359 /* Register the I/O Ports */
1360 RegisterIoPort(VGA_AC_WRITE
, VgaReadPort
, VgaWritePort
);
1361 RegisterIoPort(VGA_AC_READ
, VgaReadPort
, VgaWritePort
);
1362 RegisterIoPort(VGA_SEQ_INDEX
, VgaReadPort
, VgaWritePort
);
1363 RegisterIoPort(VGA_SEQ_DATA
, VgaReadPort
, VgaWritePort
);
1364 RegisterIoPort(VGA_DAC_READ_INDEX
, VgaReadPort
, VgaWritePort
);
1365 RegisterIoPort(VGA_DAC_WRITE_INDEX
, VgaReadPort
, VgaWritePort
);
1366 RegisterIoPort(VGA_DAC_DATA
, VgaReadPort
, VgaWritePort
);
1367 RegisterIoPort(VGA_MISC_READ
, VgaReadPort
, VgaWritePort
);
1368 RegisterIoPort(VGA_MISC_WRITE
, VgaReadPort
, VgaWritePort
);
1369 RegisterIoPort(VGA_CRTC_INDEX
, VgaReadPort
, VgaWritePort
);
1370 RegisterIoPort(VGA_CRTC_DATA
, VgaReadPort
, VgaWritePort
);
1371 RegisterIoPort(VGA_GC_INDEX
, VgaReadPort
, VgaWritePort
);
1372 RegisterIoPort(VGA_GC_DATA
, VgaReadPort
, VgaWritePort
);
1373 RegisterIoPort(VGA_STAT_MONO
, VgaReadPort
, VgaWritePort
);
1374 RegisterIoPort(VGA_STAT_COLOR
, VgaReadPort
, VgaWritePort
);
1376 /* Return success */