a6f80a79d68930f61552b87987c38eec8c4f397f
[reactos.git] / subsystems / ntvdm / vga.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: vga.c
5 * PURPOSE: VGA hardware emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #define NDEBUG
12
13 #include "vga.h"
14 #include "bios.h"
15
16 /* PRIVATE VARIABLES **********************************************************/
17
18 static CONST DWORD MemoryBase[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
19 static CONST DWORD MemoryLimit[] = { 0xAFFFF, 0xAFFFF, 0xB7FFF, 0xBFFFF };
20
21 static CONST COLORREF VgaDefaultPalette[VGA_MAX_COLORS] =
22 {
23 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
24 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
25 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
26 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
27 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
28 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
29 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
30 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
31 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
32 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
33 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
34 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
35 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
36 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
37 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
38 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
39 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
40 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
41 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
42 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
43 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
44 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
45 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
46 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
47 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
48 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
49 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
50 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
51 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
52 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
53 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
54 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
55 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
56 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
57 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
58 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
59 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
60 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
61 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
62 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
63 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
64 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
65 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
66 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
67 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
68 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
69 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
70 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
71 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
72 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
73 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
74 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
75 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
76 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
77 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
78 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
79 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
80 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
81 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
82 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
83 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
84 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
85 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
86 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
87 };
88
89 static BYTE VgaMemory[VGA_NUM_BANKS * VGA_BANK_SIZE];
90 static LPVOID ConsoleFramebuffer = NULL;
91 static HANDLE TextConsoleBuffer = NULL;
92 static HANDLE GraphicsConsoleBuffer = NULL;
93 static HANDLE ConsoleMutex = NULL;
94 static HPALETTE PaletteHandle = NULL;
95
96 static BYTE VgaLatchRegisters[VGA_NUM_BANKS] = {0, 0, 0, 0};
97 static BYTE VgaMiscRegister;
98
99 static BYTE VgaSeqIndex = VGA_SEQ_RESET_REG;
100 static BYTE VgaSeqRegisters[VGA_SEQ_MAX_REG];
101
102 static BYTE VgaGcIndex = VGA_GC_RESET_REG;
103 static BYTE VgaGcRegisters[VGA_GC_MAX_REG];
104
105 static BYTE VgaCrtcIndex = VGA_CRTC_HORZ_TOTAL_REG;
106 static BYTE VgaCrtcRegisters[VGA_CRTC_MAX_REG];
107
108 static BYTE VgaAcIndex = VGA_AC_PAL_0_REG;
109 static BOOLEAN VgaAcLatch = FALSE;
110 static BYTE VgaAcRegisters[VGA_AC_MAX_REG];
111
112 static WORD VgaDacIndex = 0;
113 static BOOLEAN VgaDacReadWrite = FALSE;
114 static BYTE VgaDacRegisters[VGA_PALETTE_SIZE];
115
116 static BOOLEAN InVerticalRetrace = FALSE;
117 static BOOLEAN InHorizontalRetrace = FALSE;
118
119 static BOOLEAN NeedsUpdate = FALSE;
120 static BOOLEAN ModeChanged = TRUE;
121 static BOOLEAN CursorMoved = FALSE;
122 static BOOLEAN PaletteChanged = FALSE;
123 static BOOLEAN TextMode = TRUE;
124
125 static SMALL_RECT UpdateRectangle = { 0, 0, 0, 0 };
126
127 /* PRIVATE FUNCTIONS **********************************************************/
128
129 static inline INT VgaGetAddressSize(VOID)
130 {
131 if (VgaCrtcRegisters[VGA_CRTC_UNDERLINE_REG] & VGA_CRTC_UNDERLINE_DWORD)
132 {
133 /* Double-word addressing */
134 return 4;
135 }
136
137 if (VgaCrtcRegisters[VGA_CRTC_MODE_CONTROL_REG] & VGA_CRTC_MODE_CONTROL_BYTE)
138 {
139 /* Byte addressing */
140 return 1;
141 }
142
143 /* Word addressing */
144 return 2;
145 }
146
147 static inline DWORD VgaTranslateReadAddress(DWORD Address)
148 {
149 DWORD Offset = Address - VgaGetVideoBaseAddress();
150 BYTE Plane;
151
152 /* Check for chain-4 and odd-even mode */
153 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
154 {
155 /* The lowest two bits are the plane number */
156 Plane = Offset & 3;
157 Offset >>= 2;
158 }
159 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
160 {
161 /* The LSB is the plane number */
162 Plane = Offset & 1;
163 Offset >>= 1;
164 }
165 else
166 {
167 /* Use the read mode */
168 Plane = VgaGcRegisters[VGA_GC_READ_MAP_SEL_REG] & 0x03;
169 }
170
171 /* Multiply the offset by the address size */
172 Offset *= VgaGetAddressSize();
173
174 return Offset + Plane * VGA_BANK_SIZE;
175 }
176
177 static inline DWORD VgaTranslateWriteAddress(DWORD Address)
178 {
179 DWORD Offset = Address - VgaGetVideoBaseAddress();
180
181 /* Check for chain-4 and odd-even mode */
182 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
183 {
184 /* Shift the offset to the right by 2 */
185 Offset >>= 2;
186 }
187 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
188 {
189 /* Shift the offset to the right by 1 */
190 Offset >>= 1;
191 }
192
193 /* Multiply the offset by the address size */
194 Offset *= VgaGetAddressSize();
195
196 /* Return the offset on plane 0 */
197 return Offset;
198 }
199
200 static inline BYTE VgaTranslateByteForWriting(BYTE Data, BYTE Plane)
201 {
202 BYTE WriteMode = VgaGcRegisters[VGA_GC_MODE_REG] & 3;
203 BYTE LogicalOperation = (VgaGcRegisters[VGA_GC_ROTATE_REG] >> 3) & 3;
204 BYTE RotateCount = VgaGcRegisters[VGA_GC_ROTATE_REG] & 7;
205 BYTE BitMask = VgaGcRegisters[VGA_GC_BITMASK_REG];
206
207 if (WriteMode == 1)
208 {
209 /* In write mode 1 just return the latch register */
210 return VgaLatchRegisters[Plane];
211 }
212
213 if (WriteMode != 2)
214 {
215 /* Write modes 0 and 3 rotate the data to the right first */
216 Data = LOBYTE(((DWORD)Data >> RotateCount) | ((DWORD)Data << (8 - RotateCount)));
217 }
218 else
219 {
220 /* Write mode 2 expands the appropriate bit to all 8 bits */
221 Data = (Data & (1 << Plane)) ? 0xFF : 0x00;
222 }
223
224 if (WriteMode == 0)
225 {
226 /*
227 * In write mode 0, the enable set/reset register decides if the
228 * set/reset bit should be expanded to all 8 bits.
229 */
230 if (VgaGcRegisters[VGA_GC_ENABLE_RESET_REG] & (1 << Plane))
231 {
232 /* Copy the bit from the set/reset register to all 8 bits */
233 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
234 }
235 }
236
237 if (WriteMode != 3)
238 {
239 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
240 if (LogicalOperation == 1) Data &= VgaLatchRegisters[Plane];
241 else if (LogicalOperation == 2) Data |= VgaLatchRegisters[Plane];
242 else if (LogicalOperation == 3) Data ^= VgaLatchRegisters[Plane];
243 }
244 else
245 {
246 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
247 BitMask &= Data;
248
249 /* Then we expand the bit in the set/reset field */
250 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
251 }
252
253 /* Bits cleared in the bitmask are replaced with latch register bits */
254 Data = (Data & BitMask) | (VgaLatchRegisters[Plane] & (~BitMask));
255
256 /* Return the byte */
257 return Data;
258 }
259
260 static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column)
261 {
262 DPRINT("VgaMarkForUpdate: Row %d, Column %d\n", Row, Column);
263
264 /* Check if this is the first time the rectangle is updated */
265 if (!NeedsUpdate)
266 {
267 UpdateRectangle.Left = UpdateRectangle.Top = SHRT_MAX;
268 UpdateRectangle.Right = UpdateRectangle.Bottom = SHRT_MIN;
269 }
270
271 /* Expand the rectangle to include the point */
272 UpdateRectangle.Left = min(UpdateRectangle.Left, Column);
273 UpdateRectangle.Right = max(UpdateRectangle.Right, Column);
274 UpdateRectangle.Top = min(UpdateRectangle.Top, Row);
275 UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Row);
276
277 /* Set the update request flag */
278 NeedsUpdate = TRUE;
279 }
280
281 static VOID VgaWriteSequencer(BYTE Data)
282 {
283 ASSERT(VgaSeqIndex < VGA_SEQ_MAX_REG);
284
285 /* Save the value */
286 VgaSeqRegisters[VgaSeqIndex] = Data;
287 }
288
289 static VOID VgaWriteGc(BYTE Data)
290 {
291 ASSERT(VgaGcIndex < VGA_GC_MAX_REG);
292
293 /* Save the value */
294 VgaGcRegisters[VgaGcIndex] = Data;
295
296 /* Check the index */
297 switch (VgaGcIndex)
298 {
299 case VGA_GC_MISC_REG:
300 {
301 /* The GC misc register decides if it's text or graphics mode */
302 ModeChanged = TRUE;
303
304 break;
305 }
306 }
307 }
308
309 static VOID VgaWriteCrtc(BYTE Data)
310 {
311 ASSERT(VgaGcIndex < VGA_CRTC_MAX_REG);
312
313 /* Save the value */
314 VgaCrtcRegisters[VgaCrtcIndex] = Data;
315
316 /* Check the index */
317 switch (VgaCrtcIndex)
318 {
319 case VGA_CRTC_END_HORZ_DISP_REG:
320 case VGA_CRTC_VERT_DISP_END_REG:
321 case VGA_CRTC_OVERFLOW_REG:
322 {
323 /* The video mode has changed */
324 ModeChanged = TRUE;
325
326 break;
327 }
328
329 case VGA_CRTC_CURSOR_LOC_LOW_REG:
330 case VGA_CRTC_CURSOR_LOC_HIGH_REG:
331 case VGA_CRTC_CURSOR_START_REG:
332 case VGA_CRTC_CURSOR_END_REG:
333 {
334 /* Set the cursor moved flag */
335 CursorMoved = TRUE;
336
337 break;
338 }
339 }
340 }
341
342 static VOID VgaWriteDac(BYTE Data)
343 {
344 INT PaletteIndex;
345 PALETTEENTRY Entry;
346
347 /* Set the value */
348 VgaDacRegisters[VgaDacIndex] = Data;
349
350 /* Find the palette index */
351 PaletteIndex = VgaDacIndex / 3;
352
353 /* Fill the entry structure */
354 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3]);
355 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 1]);
356 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 2]);
357 Entry.peFlags = 0;
358
359 /* Update the palette entry */
360 SetPaletteEntries(PaletteHandle, PaletteIndex, 1, &Entry);
361
362 /* Set the palette change flag */
363 PaletteChanged = TRUE;
364
365 /* Update the index */
366 VgaDacIndex++;
367 VgaDacIndex %= VGA_PALETTE_SIZE;
368 }
369
370 static VOID VgaWriteAc(BYTE Data)
371 {
372 ASSERT(VgaAcIndex < VGA_AC_MAX_REG);
373
374 /* Save the value */
375 VgaAcRegisters[VgaAcIndex] = Data;
376 }
377
378 static BOOL VgaEnterGraphicsMode(PCOORD Resolution)
379 {
380 DWORD i;
381 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo;
382 BYTE BitmapInfoBuffer[VGA_BITMAP_INFO_SIZE];
383 LPBITMAPINFO BitmapInfo = (LPBITMAPINFO)BitmapInfoBuffer;
384 LPWORD PaletteIndex = (LPWORD)(BitmapInfo->bmiColors);
385
386 /* Fill the bitmap info header */
387 ZeroMemory(&BitmapInfo->bmiHeader, sizeof(BITMAPINFOHEADER));
388 BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
389 BitmapInfo->bmiHeader.biWidth = Resolution->X;
390 BitmapInfo->bmiHeader.biHeight = Resolution->Y;
391 BitmapInfo->bmiHeader.biBitCount = 8;
392 BitmapInfo->bmiHeader.biPlanes = 1;
393 BitmapInfo->bmiHeader.biCompression = BI_RGB;
394 BitmapInfo->bmiHeader.biSizeImage = Resolution->X * Resolution->Y /* * 1 == biBitCount / 8 */;
395
396 /* Fill the palette data */
397 for (i = 0; i < (VGA_PALETTE_SIZE / 3); i++) PaletteIndex[i] = (WORD)i;
398
399 /* Fill the console graphics buffer info */
400 GraphicsBufferInfo.dwBitMapInfoLength = VGA_BITMAP_INFO_SIZE;
401 GraphicsBufferInfo.lpBitMapInfo = BitmapInfo;
402 GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS;
403
404 /* Create the buffer */
405 GraphicsConsoleBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
406 FILE_SHARE_READ | FILE_SHARE_WRITE,
407 NULL,
408 CONSOLE_GRAPHICS_BUFFER,
409 &GraphicsBufferInfo);
410 if (GraphicsConsoleBuffer == INVALID_HANDLE_VALUE) return FALSE;
411
412 /* Save the framebuffer address and mutex */
413 ConsoleFramebuffer = GraphicsBufferInfo.lpBitMap;
414 ConsoleMutex = GraphicsBufferInfo.hMutex;
415
416 /* Clear the framebuffer */
417 ZeroMemory(ConsoleFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
418
419 /* Set the active buffer */
420 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer);
421
422 /* Set the graphics mode palette */
423 SetConsolePalette(GraphicsConsoleBuffer,
424 PaletteHandle,
425 SYSPAL_NOSTATIC256);
426
427 /* Clear the text mode flag */
428 TextMode = FALSE;
429
430 return TRUE;
431 }
432
433 static VOID VgaLeaveGraphicsMode(VOID)
434 {
435 /* Release the console framebuffer mutex if needed */
436 ReleaseMutex(ConsoleMutex);
437
438 /* Switch back to the text buffer */
439 SetConsoleActiveScreenBuffer(TextConsoleBuffer);
440
441 /* Cleanup the video data */
442 CloseHandle(ConsoleMutex);
443 ConsoleMutex = NULL;
444 CloseHandle(GraphicsConsoleBuffer);
445 GraphicsConsoleBuffer = NULL;
446 }
447
448 static BOOL VgaEnterTextMode(PCOORD Resolution)
449 {
450 /* Resize the console */
451 SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
452
453 /* Allocate a framebuffer */
454 ConsoleFramebuffer = HeapAlloc(GetProcessHeap(),
455 HEAP_ZERO_MEMORY,
456 Resolution->X * Resolution->Y
457 * sizeof(CHAR_INFO));
458 if (ConsoleFramebuffer == NULL)
459 {
460 DisplayMessage(L"An unexpected error occurred!\n");
461 VdmRunning = FALSE;
462 return FALSE;
463 }
464
465 /* Set the text mode flag */
466 TextMode = TRUE;
467
468 return TRUE;
469 }
470
471 static VOID VgaLeaveTextMode(VOID)
472 {
473 /* Free the old framebuffer */
474 HeapFree(GetProcessHeap(), 0, ConsoleFramebuffer);
475 ConsoleFramebuffer = NULL;
476 }
477
478 static VOID VgaChangeMode(VOID)
479 {
480 COORD Resolution = VgaGetDisplayResolution();
481
482 /* Reset the mode change flag */
483 // ModeChanged = FALSE;
484
485 if (!TextMode)
486 {
487 /* Leave the current graphics mode */
488 VgaLeaveGraphicsMode();
489 }
490 else
491 {
492 /* Leave the current text mode */
493 VgaLeaveTextMode();
494 }
495
496 /* Check if the new mode is alphanumeric */
497 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA))
498 {
499 /* Enter new text mode */
500 if (!VgaEnterTextMode(&Resolution))
501 {
502 DisplayMessage(L"An unexpected VGA error occurred while switching into text mode.");
503 VdmRunning = FALSE;
504 return;
505 }
506 }
507 else
508 {
509 /* Enter 8-bit graphics mode */
510 if (!VgaEnterGraphicsMode(&Resolution))
511 {
512 DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode.");
513 VdmRunning = FALSE;
514 return;
515 }
516 }
517
518 /* Trigger a full update of the screen */
519 NeedsUpdate = TRUE;
520 UpdateRectangle.Left = 0;
521 UpdateRectangle.Top = 0;
522 UpdateRectangle.Right = Resolution.X;
523 UpdateRectangle.Bottom = Resolution.Y;
524
525 /* Reset the mode change flag */
526 ModeChanged = FALSE;
527 }
528
529 static VOID VgaUpdateFramebuffer(VOID)
530 {
531 INT i, j, k;
532 COORD Resolution = VgaGetDisplayResolution();
533 INT AddressSize = VgaGetAddressSize();
534 DWORD Address = (VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG] << 8)
535 + VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG];
536 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
537
538 /*
539 * If console framebuffer is NULL, that means something went wrong
540 * earlier and this is the final display refresh.
541 */
542 if (ConsoleFramebuffer == NULL) return;
543
544 /* Check if this is text mode or graphics mode */
545 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
546 {
547 /* Graphics mode */
548 PBYTE GraphicsBuffer = (PBYTE)ConsoleFramebuffer;
549
550 /*
551 * Synchronize access to the graphics framebuffer
552 * with the console framebuffer mutex.
553 */
554 WaitForSingleObject(ConsoleMutex, INFINITE);
555
556 /* Loop through the scanlines */
557 for (i = 0; i < Resolution.Y; i++)
558 {
559 /* Loop through the pixels */
560 for (j = 0; j < Resolution.X; j++)
561 {
562 BYTE PixelData = 0;
563
564 /* Check the shifting mode */
565 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256)
566 {
567 /* 4 bits shifted from each plane */
568
569 /* Check if this is 16 or 256 color mode */
570 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
571 {
572 /* One byte per pixel */
573 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
574 + (Address + (j / VGA_NUM_BANKS))
575 * AddressSize];
576 }
577 else
578 {
579 /* 4-bits per pixel */
580
581 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
582 + (Address + (j / (VGA_NUM_BANKS * 2)))
583 * AddressSize];
584
585 /* Check if we should use the highest 4 bits or lowest 4 */
586 if (((j / VGA_NUM_BANKS) % 2) == 0)
587 {
588 /* Highest 4 */
589 PixelData >>= 4;
590 }
591 else
592 {
593 /* Lowest 4 */
594 PixelData &= 0x0F;
595 }
596 }
597 }
598 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG)
599 {
600 /* Check if this is 16 or 256 color mode */
601 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
602 {
603 // TODO: NOT IMPLEMENTED
604 DPRINT1("8-bit interleaved mode is not implemented!\n");
605 }
606 else
607 {
608 /*
609 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
610 * then 2 bits shifted from plane 1 and 3 for the next 4
611 */
612 BYTE LowPlaneData = VgaMemory[((j / 4) % 2) * VGA_BANK_SIZE
613 + (Address + (j / 4)) * AddressSize];
614 BYTE HighPlaneData = VgaMemory[(((j / 4) % 2) + 2) * VGA_BANK_SIZE
615 + (Address + (j / 4)) * AddressSize];
616
617 /* Extract the two bits from each plane */
618 LowPlaneData = (LowPlaneData >> (6 - ((j % 4) * 2))) & 3;
619 HighPlaneData = (HighPlaneData >> (6 - ((j % 4) * 2))) & 3;
620
621 /* Combine them into the pixel */
622 PixelData = LowPlaneData | (HighPlaneData << 2);
623 }
624 }
625 else
626 {
627 /* 1 bit shifted from each plane */
628
629 /* Check if this is 16 or 256 color mode */
630 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
631 {
632 /* 8 bits per pixel, 2 on each plane */
633
634 for (k = 0; k < VGA_NUM_BANKS; k++)
635 {
636 /* The data is on plane k, 4 pixels per byte */
637 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
638 + (Address + (j / 4)) * AddressSize];
639
640 /* The mask of the first bit in the pair */
641 BYTE BitMask = 1 << (((3 - (j % 4)) * 2) + 1);
642
643 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
644 if (PlaneData & BitMask) PixelData |= 1 << k;
645
646 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
647 if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4);
648 }
649 }
650 else
651 {
652 /* 4 bits per pixel, 1 on each plane */
653
654 for (k = 0; k < VGA_NUM_BANKS; k++)
655 {
656 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
657 + (Address + (j / 8)) * AddressSize];
658
659 /* If the bit on that plane is set, set it */
660 if (PlaneData & (1 << (7 - (j % 8)))) PixelData |= 1 << k;
661 }
662 }
663 }
664
665 if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT))
666 {
667 /* In 16 color mode, the value is an index to the AC registers */
668 PixelData = VgaAcRegisters[PixelData];
669 }
670
671 /* Now check if the resulting pixel data has changed */
672 if (GraphicsBuffer[i * Resolution.X + j] != PixelData)
673 {
674 /* Yes, write the new value */
675 GraphicsBuffer[i * Resolution.X + j] = PixelData;
676
677 /* Mark the specified pixel as changed */
678 VgaMarkForUpdate(i, j);
679 }
680 }
681
682 /* Move to the next scanline */
683 Address += ScanlineSize;
684 }
685
686 /*
687 * Release the console framebuffer mutex
688 * so that we allow for repainting.
689 */
690 ReleaseMutex(ConsoleMutex);
691 }
692 else
693 {
694 /* Text mode */
695 PCHAR_INFO CharBuffer = (PCHAR_INFO)ConsoleFramebuffer;
696
697 /* Loop through the scanlines */
698 for (i = 0; i < Resolution.Y; i++)
699 {
700 /* Loop through the characters */
701 for (j = 0; j < Resolution.X; j++)
702 {
703 DWORD CurrentAddr = LOWORD((Address + j) * AddressSize);
704 CHAR_INFO CharInfo;
705
706 /* Plane 0 holds the character itself */
707 CharInfo.Char.AsciiChar = VgaMemory[CurrentAddr];
708
709 /* Plane 1 holds the attribute */
710 CharInfo.Attributes = VgaMemory[CurrentAddr + VGA_BANK_SIZE];
711
712 /* Now check if the resulting character data has changed */
713 if ((CharBuffer[i * Resolution.X + j].Char.AsciiChar != CharInfo.Char.AsciiChar)
714 || (CharBuffer[i * Resolution.X + j].Attributes != CharInfo.Attributes))
715 {
716 /* Yes, write the new value */
717 CharBuffer[i * Resolution.X + j] = CharInfo;
718
719 /* Mark the specified cell as changed */
720 VgaMarkForUpdate(i, j);
721 }
722 }
723
724 /* Move to the next scanline */
725 Address += ScanlineSize;
726 }
727 }
728 }
729
730 static VOID VgaUpdateTextCursor(VOID)
731 {
732 COORD Position;
733 CONSOLE_CURSOR_INFO CursorInfo;
734 BYTE CursorStart = VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x3F;
735 BYTE CursorEnd = VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] & 0x1F;
736 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
737 BYTE TextSize = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
738 WORD Location = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG],
739 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG]);
740
741 if (CursorStart < CursorEnd)
742 {
743 /* Visible cursor */
744 CursorInfo.bVisible = TRUE;
745 CursorInfo.dwSize = (100 * (CursorEnd - CursorStart)) / TextSize;
746 }
747 else
748 {
749 /* No cursor */
750 CursorInfo.bVisible = FALSE;
751 CursorInfo.dwSize = 0;
752 }
753
754 /* Add the cursor skew to the location */
755 Location += (VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] >> 5) & 3;
756
757 /* Find the coordinates of the new position */
758 Position.X = (WORD)(Location % ScanlineSize);
759 Position.Y = (WORD)(Location / ScanlineSize);
760
761 /* Update the physical cursor */
762 SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
763 SetConsoleCursorPosition(TextConsoleBuffer, Position);
764
765 /* Reset the cursor move flag */
766 CursorMoved = FALSE;
767 }
768
769 /* PUBLIC FUNCTIONS ***********************************************************/
770
771 DWORD VgaGetVideoBaseAddress(VOID)
772 {
773 return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
774 }
775
776 DWORD VgaGetVideoLimitAddress(VOID)
777 {
778 return MemoryLimit[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
779 }
780
781 COORD VgaGetDisplayResolution(VOID)
782 {
783 COORD Resolution;
784 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
785
786 /* The low 8 bits are in the display registers */
787 Resolution.X = VgaCrtcRegisters[VGA_CRTC_END_HORZ_DISP_REG];
788 Resolution.Y = VgaCrtcRegisters[VGA_CRTC_VERT_DISP_END_REG];
789
790 /* Set the top bits from the overflow register */
791 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
792 {
793 Resolution.Y |= 1 << 8;
794 }
795 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
796 {
797 Resolution.Y |= 1 << 9;
798 }
799
800 /* Increase the values by 1 */
801 Resolution.X++;
802 Resolution.Y++;
803
804 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
805 {
806 /* Multiply the horizontal resolution by the 9/8 dot mode */
807 Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
808 ? 8 : 9;
809
810 /* The horizontal resolution is halved in 8-bit mode */
811 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
812 }
813
814 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
815 {
816 /* Halve the vertical resolution */
817 Resolution.Y >>= 1;
818 }
819
820 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
821 Resolution.Y /= MaximumScanLine;
822
823 /* Return the resolution */
824 return Resolution;
825 }
826
827 VOID VgaRefreshDisplay(VOID)
828 {
829 COORD Resolution = VgaGetDisplayResolution();
830
831 DPRINT("VgaRefreshDisplay\n");
832
833 /* Change the display mode */
834 if (ModeChanged) VgaChangeMode();
835
836 /* Change the text cursor location */
837 if (CursorMoved) VgaUpdateTextCursor();
838
839 if (PaletteChanged)
840 {
841 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
842 {
843 /* Trigger a full update of the screen */
844 NeedsUpdate = TRUE;
845 UpdateRectangle.Left = 0;
846 UpdateRectangle.Top = 0;
847 UpdateRectangle.Right = Resolution.X;
848 UpdateRectangle.Bottom = Resolution.Y;
849 }
850
851 PaletteChanged = FALSE;
852 }
853
854 /* Update the contents of the framebuffer */
855 VgaUpdateFramebuffer();
856
857 /* Set the vertical retrace flag */
858 InVerticalRetrace = TRUE;
859
860 /* Ignore if there's nothing to update */
861 if (!NeedsUpdate) return;
862
863 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
864 UpdateRectangle.Left,
865 UpdateRectangle.Top,
866 UpdateRectangle.Right,
867 UpdateRectangle.Bottom);
868
869 /* Check if this is text mode or graphics mode */
870 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
871 {
872 /* Graphics mode */
873
874 /* Redraw the screen */
875 InvalidateConsoleDIBits(GraphicsConsoleBuffer, &UpdateRectangle);
876 }
877 else
878 {
879 /* Text mode */
880 COORD Origin = { UpdateRectangle.Left, UpdateRectangle.Top };
881
882 /* Write the data to the console */
883 WriteConsoleOutputA(TextConsoleBuffer,
884 (PCHAR_INFO)ConsoleFramebuffer,
885 Resolution,
886 Origin,
887 &UpdateRectangle);
888
889 }
890
891 /* Clear the update flag */
892 NeedsUpdate = FALSE;
893 }
894
895 VOID VgaHorizontalRetrace(VOID)
896 {
897 /* Set the flag */
898 InHorizontalRetrace = TRUE;
899 }
900
901 VOID VgaReadMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
902 {
903 DWORD i;
904 DWORD VideoAddress;
905
906 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n",
907 Address,
908 Size);
909
910 /* Ignore if video RAM access is disabled */
911 if (!(VgaMiscRegister & VGA_MISC_RAM_ENABLED)) return;
912
913 /* Loop through each byte */
914 for (i = 0; i < Size; i++)
915 {
916 VideoAddress = VgaTranslateReadAddress(Address + i);
917
918 /* Load the latch registers */
919 VgaLatchRegisters[0] = VgaMemory[LOWORD(VideoAddress)];
920 VgaLatchRegisters[1] = VgaMemory[VGA_BANK_SIZE + LOWORD(VideoAddress)];
921 VgaLatchRegisters[2] = VgaMemory[(2 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
922 VgaLatchRegisters[3] = VgaMemory[(3 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
923
924 /* Copy the value to the buffer */
925 Buffer[i] = VgaMemory[VideoAddress];
926 }
927 }
928
929 VOID VgaWriteMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
930 {
931 DWORD i, j;
932 DWORD VideoAddress;
933
934 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n",
935 Address,
936 Size);
937
938 /* Ignore if video RAM access is disabled */
939 if (!(VgaMiscRegister & VGA_MISC_RAM_ENABLED)) return;
940
941 /* Also ignore if write access to all planes is disabled */
942 if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return;
943
944 /* Loop through each byte */
945 for (i = 0; i < Size; i++)
946 {
947 VideoAddress = VgaTranslateWriteAddress(Address + i);
948
949 for (j = 0; j < VGA_NUM_BANKS; j++)
950 {
951 /* Make sure the page is writeable */
952 if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue;
953
954 /* Check if this is chain-4 mode */
955 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
956 {
957 if (((Address + i) & 3) != j)
958 {
959 /* This plane will not be accessed */
960 continue;
961 }
962 }
963
964 /* Check if this is odd-even mode */
965 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
966 {
967 if (((Address + i) & 1) != (j & 1))
968 {
969 /* This plane will not be accessed */
970 continue;
971 }
972 }
973
974 /* Copy the value to the VGA memory */
975 VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(Buffer[i], j);
976 }
977 }
978 }
979
980 BYTE VgaReadPort(WORD Port)
981 {
982 DPRINT("VgaReadPort: Port 0x%04X\n", Port);
983
984 switch (Port)
985 {
986 case VGA_AC_INDEX:
987 {
988 return VgaAcIndex;
989 }
990
991 case VGA_AC_READ:
992 {
993 return VgaAcRegisters[VgaAcIndex];
994 }
995
996 case VGA_SEQ_INDEX:
997 {
998 return VgaSeqIndex;
999 }
1000
1001 case VGA_SEQ_DATA:
1002 {
1003 return VgaSeqRegisters[VgaSeqIndex];
1004 }
1005
1006 case VGA_DAC_READ_INDEX:
1007 {
1008 /* This returns the read/write state */
1009 return VgaDacReadWrite ? 0 : 3;
1010 }
1011
1012 case VGA_DAC_WRITE_INDEX:
1013 {
1014 return VgaDacIndex / 3;
1015 }
1016
1017 case VGA_DAC_DATA:
1018 {
1019 /* Ignore reads in write mode */
1020 if (!VgaDacReadWrite)
1021 {
1022 BYTE Data = VgaDacRegisters[VgaDacIndex++];
1023 VgaDacIndex %= VGA_PALETTE_SIZE;
1024 return Data;
1025 }
1026
1027 break;
1028 }
1029
1030 case VGA_MISC_READ:
1031 {
1032 return VgaMiscRegister;
1033 }
1034
1035 case VGA_CRTC_INDEX:
1036 {
1037 return VgaCrtcIndex;
1038 }
1039
1040 case VGA_CRTC_DATA:
1041 {
1042 return VgaCrtcRegisters[VgaCrtcIndex];
1043 }
1044
1045 case VGA_GC_INDEX:
1046 {
1047 return VgaGcIndex;
1048 }
1049
1050 case VGA_GC_DATA:
1051 {
1052 return VgaGcRegisters[VgaGcIndex];
1053 }
1054
1055 case VGA_STAT_MONO:
1056 case VGA_STAT_COLOR:
1057 {
1058 BYTE Result = 0;
1059
1060 /* Reset the AC latch */
1061 VgaAcLatch = FALSE;
1062
1063 /* Set a flag if there is a vertical or horizontal retrace */
1064 if (InVerticalRetrace || InHorizontalRetrace) Result |= VGA_STAT_DD;
1065
1066 /* Set an additional flag if there was a vertical retrace */
1067 if (InVerticalRetrace) Result |= VGA_STAT_VRETRACE;
1068
1069 /* Clear the flags */
1070 InHorizontalRetrace = InVerticalRetrace = FALSE;
1071
1072 return Result;
1073 }
1074 }
1075
1076 return 0;
1077 }
1078
1079 VOID VgaWritePort(WORD Port, BYTE Data)
1080 {
1081 DPRINT("VgaWritePort: Port 0x%04X, Data 0x%02X\n", Port, Data);
1082
1083 switch (Port)
1084 {
1085 case VGA_AC_INDEX:
1086 {
1087 if (!VgaAcLatch)
1088 {
1089 /* Change the index */
1090 if (Data < VGA_AC_MAX_REG) VgaAcIndex = Data;
1091 }
1092 else
1093 {
1094 /* Write the data */
1095 VgaWriteAc(Data);
1096 }
1097
1098 /* Toggle the latch */
1099 VgaAcLatch = !VgaAcLatch;
1100
1101 break;
1102 }
1103
1104 case VGA_SEQ_INDEX:
1105 {
1106 /* Set the sequencer index register */
1107 if (Data < VGA_SEQ_MAX_REG) VgaSeqIndex = Data;
1108 break;
1109 }
1110
1111 case VGA_SEQ_DATA:
1112 {
1113 /* Call the sequencer function */
1114 VgaWriteSequencer(Data);
1115 break;
1116 }
1117
1118 case VGA_DAC_READ_INDEX:
1119 {
1120 VgaDacReadWrite = FALSE;
1121 VgaDacIndex = Data * 3;
1122 break;
1123 }
1124
1125 case VGA_DAC_WRITE_INDEX:
1126 {
1127 VgaDacReadWrite = TRUE;
1128 VgaDacIndex = Data * 3;
1129 break;
1130 }
1131
1132 case VGA_DAC_DATA:
1133 {
1134 /* Ignore writes in read mode */
1135 if (VgaDacReadWrite) VgaWriteDac(Data & 0x3F);
1136 break;
1137 }
1138
1139 case VGA_MISC_WRITE:
1140 {
1141 VgaMiscRegister = Data;
1142 break;
1143 }
1144
1145 case VGA_CRTC_INDEX:
1146 {
1147 /* Set the CRTC index register */
1148 if (Data < VGA_CRTC_MAX_REG) VgaCrtcIndex = Data;
1149 break;
1150 }
1151
1152 case VGA_CRTC_DATA:
1153 {
1154 /* Call the CRTC function */
1155 VgaWriteCrtc(Data);
1156 break;
1157 }
1158
1159 case VGA_GC_INDEX:
1160 {
1161 /* Set the GC index register */
1162 if (Data < VGA_GC_MAX_REG) VgaGcIndex = Data;
1163 break;
1164 }
1165
1166 case VGA_GC_DATA:
1167 {
1168 /* Call the GC function */
1169 VgaWriteGc(Data);
1170 break;
1171 }
1172 }
1173 }
1174
1175 VOID VgaClearMemory(VOID)
1176 {
1177 ZeroMemory(VgaMemory, sizeof(VgaMemory));
1178 }
1179
1180 BOOLEAN VgaInitialize(HANDLE TextHandle)
1181 {
1182 INT i, j;
1183 COORD Resolution;
1184 INT AddressSize;
1185 DWORD ScanlineSize;
1186 COORD Origin = { 0, 0 };
1187 SMALL_RECT ScreenRect;
1188 PCHAR_INFO CharBuffer;
1189 DWORD Address = 0;
1190 DWORD CurrentAddr;
1191 LPLOGPALETTE Palette;
1192
1193 /* Set the global handle */
1194 TextConsoleBuffer = TextHandle;
1195
1196 /* Clear the VGA memory */
1197 VgaClearMemory();
1198
1199 /* Set the default video mode */
1200 BiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE);
1201 VgaChangeMode();
1202
1203 /* Get the data */
1204 Resolution = VgaGetDisplayResolution();
1205 CharBuffer = (PCHAR_INFO)ConsoleFramebuffer;
1206 AddressSize = VgaGetAddressSize();
1207 ScreenRect.Left = ScreenRect.Top = 0;
1208 ScreenRect.Right = Resolution.X;
1209 ScreenRect.Bottom = Resolution.Y;
1210 ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1211
1212 /* Read the data from the console into the framebuffer */
1213 ReadConsoleOutputA(TextConsoleBuffer,
1214 CharBuffer,
1215 Resolution,
1216 Origin,
1217 &ScreenRect);
1218
1219 /* Loop through the scanlines */
1220 for (i = 0; i < Resolution.Y; i++)
1221 {
1222 /* Loop through the characters */
1223 for (j = 0; j < Resolution.X; j++)
1224 {
1225 CurrentAddr = LOWORD((Address + j) * AddressSize);
1226
1227 /* Store the character in plane 0 */
1228 VgaMemory[CurrentAddr] = CharBuffer[i * Resolution.X + j].Char.AsciiChar;
1229
1230 /* Store the attribute in plane 1 */
1231 VgaMemory[CurrentAddr + VGA_BANK_SIZE] = (BYTE)CharBuffer[i * Resolution.X + j].Attributes;
1232 }
1233
1234 /* Move to the next scanline */
1235 Address += ScanlineSize;
1236 }
1237
1238 /* Allocate storage space for the palette */
1239 Palette = (LPLOGPALETTE)HeapAlloc(GetProcessHeap(),
1240 HEAP_ZERO_MEMORY,
1241 sizeof(LOGPALETTE)
1242 + VGA_MAX_COLORS * sizeof(PALETTEENTRY));
1243 if (Palette == NULL) return FALSE;
1244
1245 /* Initialize the palette */
1246 Palette->palVersion = 0x0300;
1247 Palette->palNumEntries = VGA_MAX_COLORS;
1248
1249 /* Copy the colors of the default palette to the DAC and console palette */
1250 for (i = 0; i < VGA_MAX_COLORS; i++)
1251 {
1252 /* Set the palette entries */
1253 Palette->palPalEntry[i].peRed = GetRValue(VgaDefaultPalette[i]);
1254 Palette->palPalEntry[i].peGreen = GetGValue(VgaDefaultPalette[i]);
1255 Palette->palPalEntry[i].peBlue = GetBValue(VgaDefaultPalette[i]);
1256 Palette->palPalEntry[i].peFlags = 0;
1257
1258 /* Set the DAC registers */
1259 VgaDacRegisters[i * 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette[i]));
1260 VgaDacRegisters[i * 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette[i]));
1261 VgaDacRegisters[i * 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette[i]));
1262 }
1263
1264 /* Create the palette */
1265 PaletteHandle = CreatePalette(Palette);
1266
1267 /* Free the palette */
1268 HeapFree(GetProcessHeap(), 0, Palette);
1269
1270 /* Return success if the palette was successfully created */
1271 return (PaletteHandle ? TRUE : FALSE);
1272 }
1273
1274 /* EOF */