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 };
25 /*static*/ CONST COLORREF EgaPalette
[VGA_MAX_COLORS
/ 4] =
27 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
28 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0xAA, 0x00), RGB(0xAA, 0xAA, 0xAA),
29 RGB(0x00, 0x00, 0x55), RGB(0x00, 0x00, 0xFF), RGB(0x00, 0xAA, 0x55), RGB(0x00, 0xAA, 0xFF),
30 RGB(0xAA, 0x00, 0x55), RGB(0xAA, 0x00, 0xFF), RGB(0xAA, 0xAA, 0x55), RGB(0xAA, 0xAA, 0xFF),
31 RGB(0x00, 0x55, 0x00), RGB(0x00, 0x55, 0xAA), RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0xAA),
32 RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0x55, 0xAA), RGB(0xAA, 0xFF, 0x00), RGB(0xAA, 0xFF, 0xAA),
33 RGB(0x00, 0x55, 0x55), RGB(0x00, 0x55, 0xFF), RGB(0x00, 0xFF, 0x55), RGB(0x00, 0xFF, 0xFF),
34 RGB(0xAA, 0x55, 0x55), RGB(0xAA, 0x55, 0xFF), RGB(0xAA, 0xFF, 0x55), RGB(0xAA, 0xFF, 0xFF),
35 RGB(0x55, 0x00, 0x00), RGB(0x55, 0x00, 0xAA), RGB(0x55, 0xAA, 0x00), RGB(0x55, 0xAA, 0xAA),
36 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x00, 0xAA), RGB(0xFF, 0xAA, 0x00), RGB(0xFF, 0xAA, 0xAA),
37 RGB(0x55, 0x00, 0x55), RGB(0x55, 0x00, 0xFF), RGB(0x55, 0xAA, 0x55), RGB(0x55, 0xAA, 0xFF),
38 RGB(0xFF, 0x00, 0x55), RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0xAA, 0x55), RGB(0xFF, 0xAA, 0xFF),
39 RGB(0x55, 0x55, 0x00), RGB(0x55, 0x55, 0xAA), RGB(0x55, 0xFF, 0x00), RGB(0x55, 0xFF, 0xAA),
40 RGB(0xFF, 0x55, 0x00), RGB(0xFF, 0x55, 0xAA), RGB(0xFF, 0xFF, 0x00), RGB(0xFF, 0xFF, 0xAA),
41 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
42 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF)
45 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
47 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
48 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
49 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
50 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
51 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
52 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
53 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
54 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
55 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
56 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
57 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
58 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
59 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
60 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
61 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
62 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
63 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
64 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
65 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
66 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
67 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
68 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
69 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
70 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
71 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
72 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
73 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
74 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
75 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
76 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
77 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
78 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
79 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
80 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
81 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
82 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
83 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
84 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
85 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
86 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
87 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
88 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
89 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
90 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
91 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
92 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
93 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
94 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
95 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
96 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
97 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
98 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
99 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
100 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
101 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
102 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
103 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
104 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
105 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
106 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
107 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
108 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
109 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
110 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
113 static BYTE VgaMemory
[VGA_NUM_BANKS
* VGA_BANK_SIZE
];
114 static LPVOID ConsoleFramebuffer
= NULL
;
115 static HANDLE TextConsoleBuffer
= NULL
;
116 static HANDLE GraphicsConsoleBuffer
= NULL
;
117 static HANDLE ConsoleMutex
= NULL
;
118 static HPALETTE PaletteHandle
= NULL
;
119 static BOOLEAN DoubleVision
= FALSE
;
121 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
123 static BYTE VgaMiscRegister
;
124 static BYTE VgaFeatureRegister
;
126 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
127 static BYTE VgaSeqRegisters
[VGA_SEQ_MAX_REG
];
129 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
130 static BYTE VgaCrtcRegisters
[VGA_CRTC_MAX_REG
];
132 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
133 static BYTE VgaGcRegisters
[VGA_GC_MAX_REG
];
135 static BOOLEAN VgaAcLatch
= FALSE
;
136 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
137 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
139 // static VGA_REGISTERS VgaRegisters;
141 static BYTE VgaDacMask
= 0xFF;
142 static WORD VgaDacIndex
= 0;
143 static BOOLEAN VgaDacReadWrite
= FALSE
;
144 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
146 static BOOLEAN InVerticalRetrace
= FALSE
;
147 static BOOLEAN InHorizontalRetrace
= FALSE
;
149 static BOOLEAN NeedsUpdate
= FALSE
;
150 static BOOLEAN ModeChanged
= TRUE
;
151 static BOOLEAN CursorMoved
= FALSE
;
152 static BOOLEAN PaletteChanged
= FALSE
;
159 } ScreenMode
= TEXT_MODE
;
161 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
163 /* PRIVATE FUNCTIONS **********************************************************/
165 static inline INT
VgaGetAddressSize(VOID
)
167 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
169 /* Double-word addressing */
170 return 4; // sizeof(DWORD)
173 if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
175 /* Byte addressing */
176 return 1; // sizeof(BYTE)
179 /* Word addressing */
180 return 2; // sizeof(WORD)
183 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
185 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
188 /* Check for chain-4 and odd-even mode */
189 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
191 /* The lowest two bits are the plane number */
195 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
197 /* The LSB is the plane number */
203 /* Use the read mode */
204 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
207 /* Multiply the offset by the address size */
208 Offset
*= VgaGetAddressSize();
210 return Offset
+ Plane
* VGA_BANK_SIZE
;
213 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
215 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
217 /* Check for chain-4 and odd-even mode */
218 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
220 /* Shift the offset to the right by 2 */
223 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
225 /* Shift the offset to the right by 1 */
229 /* Multiply the offset by the address size */
230 Offset
*= VgaGetAddressSize();
232 /* Return the offset on plane 0 */
236 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
238 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 3;
239 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
243 /* In write mode 1 just return the latch register */
244 return VgaLatchRegisters
[Plane
];
249 /* Write modes 0 and 3 rotate the data to the right first */
250 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 7;
251 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
255 /* Write mode 2 expands the appropriate bit to all 8 bits */
256 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
262 * In write mode 0, the enable set/reset register decides if the
263 * set/reset bit should be expanded to all 8 bits.
265 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
267 /* Copy the bit from the set/reset register to all 8 bits */
268 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
274 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
275 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 3;
277 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
278 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
279 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
283 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
286 /* Then we expand the bit in the set/reset field */
287 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
290 /* Bits cleared in the bitmask are replaced with latch register bits */
291 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
293 /* Return the byte */
297 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
299 /* Check if this is the first time the rectangle is updated */
302 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
303 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
306 /* Expand the rectangle to include the point */
307 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
308 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
309 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
310 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
312 /* Set the update request flag */
316 static VOID
VgaWriteSequencer(BYTE Data
)
318 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
321 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
324 static VOID
VgaWriteGc(BYTE Data
)
326 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
329 VgaGcRegisters
[VgaGcIndex
] = Data
;
331 /* Check the index */
334 case VGA_GC_MISC_REG
:
336 /* The GC misc register decides if it's text or graphics mode */
343 static VOID
VgaWriteCrtc(BYTE Data
)
345 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
348 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
350 /* Check the index */
351 switch (VgaCrtcIndex
)
353 case VGA_CRTC_END_HORZ_DISP_REG
:
354 case VGA_CRTC_VERT_DISP_END_REG
:
355 case VGA_CRTC_OVERFLOW_REG
:
357 /* The video mode has changed */
362 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
363 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
364 case VGA_CRTC_CURSOR_START_REG
:
365 case VGA_CRTC_CURSOR_END_REG
:
367 /* Set the cursor moved flag */
374 static VOID
VgaWriteDac(BYTE Data
)
380 VgaDacRegisters
[VgaDacIndex
] = Data
;
382 /* Find the palette index */
383 PaletteIndex
= VgaDacIndex
/ 3;
385 /* Fill the entry structure */
386 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3]);
387 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 1]);
388 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 2]);
391 /* Update the palette entry */
392 SetPaletteEntries(PaletteHandle
, PaletteIndex
, 1, &Entry
);
394 /* Set the palette change flag */
395 PaletteChanged
= TRUE
;
397 /* Update the index */
399 VgaDacIndex
%= VGA_PALETTE_SIZE
;
402 static VOID
VgaWriteAc(BYTE Data
)
404 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
407 VgaAcRegisters
[VgaAcIndex
] = Data
;
409 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
411 /* Set the palette change flag */
412 PaletteChanged
= TRUE
;
416 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
420 /* Copy the colors of the default palette to the DAC and console palette */
421 for (i
= 0; i
< NumOfEntries
; i
++)
423 /* Set the palette entries */
424 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
425 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
426 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
427 Entries
[i
].peFlags
= 0;
429 /* Set the DAC registers */
430 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
431 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
432 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
436 static BOOLEAN
VgaInitializePalette(VOID
)
438 LPLOGPALETTE Palette
;
440 /* Allocate storage space for the palette */
441 Palette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
444 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
445 if (Palette
== NULL
) return FALSE
;
447 /* Initialize the palette */
448 Palette
->palVersion
= 0x0300;
449 Palette
->palNumEntries
= VGA_MAX_COLORS
;
451 /* Restore the default palette */
452 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
454 /* Create the palette */
455 PaletteHandle
= CreatePalette(Palette
);
457 /* Free the palette */
458 HeapFree(GetProcessHeap(), 0, Palette
);
460 /* Fail if the palette wasn't successfully created... */
461 if (PaletteHandle
== NULL
) return FALSE
;
463 /* ... otherwise return success */
467 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
470 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
471 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
472 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
473 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
475 LONG Width
= Resolution
->X
;
476 LONG Height
= Resolution
->Y
;
478 /* Use DoubleVision mode if the resolution is too small */
479 if (Width
< VGA_MINIMUM_WIDTH
&& Height
< VGA_MINIMUM_HEIGHT
)
486 /* Fill the bitmap info header */
487 ZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BITMAPINFOHEADER
));
488 BitmapInfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
489 BitmapInfo
->bmiHeader
.biWidth
= Width
;
490 BitmapInfo
->bmiHeader
.biHeight
= Height
;
491 BitmapInfo
->bmiHeader
.biBitCount
= 8;
492 BitmapInfo
->bmiHeader
.biPlanes
= 1;
493 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
494 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
496 /* Fill the palette data */
497 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
499 /* Fill the console graphics buffer info */
500 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
501 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
502 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
504 /* Create the buffer */
505 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
506 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
508 CONSOLE_GRAPHICS_BUFFER
,
509 &GraphicsBufferInfo
);
510 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
512 /* Save the framebuffer address and mutex */
513 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
514 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
516 /* Clear the framebuffer */
517 ZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
519 /* Set the active buffer */
520 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer
);
522 /* Set the graphics mode palette */
523 SetConsolePalette(GraphicsConsoleBuffer
,
527 /* Set the screen mode flag */
528 ScreenMode
= GRAPHICS_MODE
;
533 static VOID
VgaLeaveGraphicsMode(VOID
)
535 /* Release the console framebuffer mutex if needed */
536 ReleaseMutex(ConsoleMutex
);
538 /* Switch back to the text buffer */
539 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
541 /* Cleanup the video data */
542 CloseHandle(ConsoleMutex
);
544 CloseHandle(GraphicsConsoleBuffer
);
545 GraphicsConsoleBuffer
= NULL
;
546 DoubleVision
= FALSE
;
549 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
551 /* Resize the console */
552 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
554 /* Allocate a framebuffer */
555 ConsoleFramebuffer
= HeapAlloc(GetProcessHeap(),
557 Resolution
->X
* Resolution
->Y
558 * sizeof(CHAR_INFO
));
559 if (ConsoleFramebuffer
== NULL
)
561 DisplayMessage(L
"An unexpected error occurred!\n");
567 * Set the text mode palette.
569 * WARNING: This call should fail on Windows (and therefore
570 * we get the default palette and our external behaviour is
571 * just like Windows' one), but it should success on ReactOS
572 * (so that we get console palette changes even for text-mode
573 * screen-buffers, which is a new feature on ReactOS).
575 SetConsolePalette(TextConsoleBuffer
,
579 /* Set the screen mode flag */
580 ScreenMode
= TEXT_MODE
;
585 static VOID
VgaLeaveTextMode(VOID
)
587 /* Free the old framebuffer */
588 HeapFree(GetProcessHeap(), 0, ConsoleFramebuffer
);
589 ConsoleFramebuffer
= NULL
;
592 static VOID
VgaChangeMode(VOID
)
594 COORD Resolution
= VgaGetDisplayResolution();
596 /* Reset the mode change flag */
597 // ModeChanged = FALSE;
599 if (ScreenMode
== GRAPHICS_MODE
)
601 /* Leave the current graphics mode */
602 VgaLeaveGraphicsMode();
606 /* Leave the current text mode */
610 /* Check if the new mode is alphanumeric */
611 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
))
613 /* Enter new text mode */
614 if (!VgaEnterTextMode(&Resolution
))
616 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode.");
623 /* Enter 8-bit graphics mode */
624 if (!VgaEnterGraphicsMode(&Resolution
))
626 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode.");
632 /* Trigger a full update of the screen */
634 UpdateRectangle
.Left
= 0;
635 UpdateRectangle
.Top
= 0;
636 UpdateRectangle
.Right
= Resolution
.X
;
637 UpdateRectangle
.Bottom
= Resolution
.Y
;
639 /* Reset the mode change flag */
643 static VOID
VgaUpdateFramebuffer(VOID
)
646 COORD Resolution
= VgaGetDisplayResolution();
647 INT AddressSize
= VgaGetAddressSize();
648 DWORD Address
= (VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
] << 8)
649 + VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
];
650 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
653 * If console framebuffer is NULL, that means something went wrong
654 * earlier and this is the final display refresh.
656 if (ConsoleFramebuffer
== NULL
) return;
658 /* Check if this is text mode or graphics mode */
659 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
662 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
665 * Synchronize access to the graphics framebuffer
666 * with the console framebuffer mutex.
668 WaitForSingleObject(ConsoleMutex
, INFINITE
);
670 /* Loop through the scanlines */
671 for (i
= 0; i
< Resolution
.Y
; i
++)
673 /* Loop through the pixels */
674 for (j
= 0; j
< Resolution
.X
; j
++)
678 /* Check the shifting mode */
679 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
681 /* 4 bits shifted from each plane */
683 /* Check if this is 16 or 256 color mode */
684 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
686 /* One byte per pixel */
687 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
688 + (Address
+ (j
/ VGA_NUM_BANKS
))
693 /* 4-bits per pixel */
695 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
696 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
699 /* Check if we should use the highest 4 bits or lowest 4 */
700 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
712 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
714 /* Check if this is 16 or 256 color mode */
715 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
717 // TODO: NOT IMPLEMENTED
718 DPRINT1("8-bit interleaved mode is not implemented!\n");
723 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
724 * then 2 bits shifted from plane 1 and 3 for the next 4
726 BYTE LowPlaneData
= VgaMemory
[((j
/ 4) % 2) * VGA_BANK_SIZE
727 + (Address
+ (j
/ 4)) * AddressSize
];
728 BYTE HighPlaneData
= VgaMemory
[(((j
/ 4) % 2) + 2) * VGA_BANK_SIZE
729 + (Address
+ (j
/ 4)) * AddressSize
];
731 /* Extract the two bits from each plane */
732 LowPlaneData
= (LowPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
733 HighPlaneData
= (HighPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
735 /* Combine them into the pixel */
736 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
741 /* 1 bit shifted from each plane */
743 /* Check if this is 16 or 256 color mode */
744 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
746 /* 8 bits per pixel, 2 on each plane */
748 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
750 /* The data is on plane k, 4 pixels per byte */
751 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
752 + (Address
+ (j
/ 4)) * AddressSize
];
754 /* The mask of the first bit in the pair */
755 BYTE BitMask
= 1 << (((3 - (j
% 4)) * 2) + 1);
757 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
758 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
760 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
761 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
766 /* 4 bits per pixel, 1 on each plane */
768 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
770 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
771 + (Address
+ (j
/ 8)) * AddressSize
];
773 /* If the bit on that plane is set, set it */
774 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
779 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
781 /* In 16 color mode, the value is an index to the AC registers */
782 PixelData
= VgaAcRegisters
[PixelData
];
785 /* Take into account DoubleVision mode when checking for pixel updates */
788 /* Now check if the resulting pixel data has changed */
789 if (GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] != PixelData
)
791 /* Yes, write the new value */
792 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] = PixelData
;
793 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2 + 1)] = PixelData
;
794 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2)] = PixelData
;
795 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
797 /* Mark the specified pixel as changed */
798 VgaMarkForUpdate(i
, j
);
803 /* Now check if the resulting pixel data has changed */
804 if (GraphicsBuffer
[i
* Resolution
.X
+ j
] != PixelData
)
806 /* Yes, write the new value */
807 GraphicsBuffer
[i
* Resolution
.X
+ j
] = PixelData
;
809 /* Mark the specified pixel as changed */
810 VgaMarkForUpdate(i
, j
);
815 /* Move to the next scanline */
816 Address
+= ScanlineSize
;
820 * Release the console framebuffer mutex
821 * so that we allow for repainting.
823 ReleaseMutex(ConsoleMutex
);
828 PCHAR_INFO CharBuffer
= (PCHAR_INFO
)ConsoleFramebuffer
;
830 /* Loop through the scanlines */
831 for (i
= 0; i
< Resolution
.Y
; i
++)
833 /* Loop through the characters */
834 for (j
= 0; j
< Resolution
.X
; j
++)
836 DWORD CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
839 /* Plane 0 holds the character itself */
840 CharInfo
.Char
.AsciiChar
= VgaMemory
[CurrentAddr
];
842 /* Plane 1 holds the attribute */
843 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
845 /* Now check if the resulting character data has changed */
846 if ((CharBuffer
[i
* Resolution
.X
+ j
].Char
.AsciiChar
!= CharInfo
.Char
.AsciiChar
)
847 || (CharBuffer
[i
* Resolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
849 /* Yes, write the new value */
850 CharBuffer
[i
* Resolution
.X
+ j
] = CharInfo
;
852 /* Mark the specified cell as changed */
853 VgaMarkForUpdate(i
, j
);
857 /* Move to the next scanline */
858 Address
+= ScanlineSize
;
863 static VOID
VgaUpdateTextCursor(VOID
)
866 CONSOLE_CURSOR_INFO CursorInfo
;
867 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x3F;
868 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
869 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
870 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
871 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
872 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
874 /* Just return if we are not in text mode */
875 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) != 0) return;
877 if (CursorStart
< CursorEnd
)
880 CursorInfo
.bVisible
= TRUE
;
881 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
886 CursorInfo
.bVisible
= FALSE
;
887 CursorInfo
.dwSize
= 0;
890 /* Add the cursor skew to the location */
891 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 3;
893 /* Find the coordinates of the new position */
894 Position
.X
= (WORD
)(Location
% ScanlineSize
);
895 Position
.Y
= (WORD
)(Location
/ ScanlineSize
);
897 /* Update the physical cursor */
898 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
899 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
901 /* Reset the cursor move flag */
905 /* PUBLIC FUNCTIONS ***********************************************************/
907 DWORD
VgaGetVideoBaseAddress(VOID
)
909 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
912 DWORD
VgaGetVideoLimitAddress(VOID
)
914 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
917 COORD
VgaGetDisplayResolution(VOID
)
920 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
922 /* The low 8 bits are in the display registers */
923 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
924 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
926 /* Set the top bits from the overflow register */
927 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
929 Resolution
.Y
|= 1 << 8;
931 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
933 Resolution
.Y
|= 1 << 9;
936 /* Increase the values by 1 */
940 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
942 /* Multiply the horizontal resolution by the 9/8 dot mode */
943 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
946 /* The horizontal resolution is halved in 8-bit mode */
947 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
950 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
952 /* Halve the vertical resolution */
956 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
957 Resolution
.Y
/= MaximumScanLine
;
959 /* Return the resolution */
963 VOID
VgaRefreshDisplay(VOID
)
965 HANDLE ConsoleBufferHandle
= NULL
;
968 /* Set the vertical retrace flag */
969 InVerticalRetrace
= TRUE
;
971 /* If nothing has changed, just return */
972 if (!ModeChanged
&& !CursorMoved
&& !PaletteChanged
&& !NeedsUpdate
)
975 /* Retrieve the current resolution */
976 Resolution
= VgaGetDisplayResolution();
978 /* Change the display mode */
979 if (ModeChanged
) VgaChangeMode();
981 /* Change the text cursor location */
982 if (CursorMoved
) VgaUpdateTextCursor();
986 /* Trigger a full update of the screen */
988 UpdateRectangle
.Left
= 0;
989 UpdateRectangle
.Top
= 0;
990 UpdateRectangle
.Right
= Resolution
.X
;
991 UpdateRectangle
.Bottom
= Resolution
.Y
;
993 PaletteChanged
= FALSE
;
996 /* Update the contents of the framebuffer */
997 VgaUpdateFramebuffer();
999 /* Ignore if there's nothing to update */
1000 if (!NeedsUpdate
) return;
1002 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1003 UpdateRectangle
.Left
,
1004 UpdateRectangle
.Top
,
1005 UpdateRectangle
.Right
,
1006 UpdateRectangle
.Bottom
);
1008 /* Check if this is text mode or graphics mode */
1009 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1012 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
1017 COORD Origin
= { UpdateRectangle
.Left
, UpdateRectangle
.Top
};
1018 ConsoleBufferHandle
= TextConsoleBuffer
;
1020 /* Write the data to the console */
1021 WriteConsoleOutputA(TextConsoleBuffer
,
1022 (PCHAR_INFO
)ConsoleFramebuffer
,
1028 /* In DoubleVision mode, scale the update rectangle */
1031 UpdateRectangle
.Left
*= 2;
1032 UpdateRectangle
.Top
*= 2;
1033 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
1034 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
1037 /* Redraw the screen */
1038 InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
1040 /* Clear the update flag */
1041 NeedsUpdate
= FALSE
;
1044 VOID
VgaHorizontalRetrace(VOID
)
1047 InHorizontalRetrace
= TRUE
;
1050 VOID
VgaReadMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1055 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1057 /* Ignore if video RAM access is disabled */
1058 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1060 /* Loop through each byte */
1061 for (i
= 0; i
< Size
; i
++)
1063 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1065 /* Load the latch registers */
1066 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1067 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1068 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1069 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1071 /* Copy the value to the buffer */
1072 Buffer
[i
] = VgaMemory
[VideoAddress
];
1076 VOID
VgaWriteMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1081 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1083 /* Ignore if video RAM access is disabled */
1084 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1086 /* Also ignore if write access to all planes is disabled */
1087 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return;
1089 /* Loop through each byte */
1090 for (i
= 0; i
< Size
; i
++)
1092 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1094 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1096 /* Make sure the page is writeable */
1097 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1099 /* Check if this is chain-4 mode */
1100 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1102 if (((Address
+ i
) & 3) != j
)
1104 /* This plane will not be accessed */
1109 /* Check if this is odd-even mode */
1110 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1112 if (((Address
+ i
) & 1) != (j
& 1))
1114 /* This plane will not be accessed */
1119 /* Copy the value to the VGA memory */
1120 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(Buffer
[i
], j
);
1125 BYTE WINAPI
VgaReadPort(ULONG Port
)
1127 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1132 return VgaMiscRegister
;
1134 case VGA_INSTAT0_READ
:
1135 return 0; // Not implemented
1137 case VGA_INSTAT1_READ_MONO
:
1138 case VGA_INSTAT1_READ_COLOR
:
1142 /* Reset the AC latch */
1145 /* Set a flag if there is a vertical or horizontal retrace */
1146 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
1148 /* Set an additional flag if there was a vertical retrace */
1149 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
1151 /* Clear the flags */
1152 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
1157 case VGA_FEATURE_READ
:
1158 return VgaFeatureRegister
;
1164 return VgaAcRegisters
[VgaAcIndex
];
1170 return VgaSeqRegisters
[VgaSeqIndex
];
1175 case VGA_DAC_READ_INDEX
:
1176 /* This returns the read/write state */
1177 return (VgaDacReadWrite
? 0 : 3);
1179 case VGA_DAC_WRITE_INDEX
:
1180 return (VgaDacIndex
/ 3);
1184 /* Ignore reads in write mode */
1185 if (!VgaDacReadWrite
)
1187 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
1188 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1195 case VGA_CRTC_INDEX_MONO
:
1196 case VGA_CRTC_INDEX_COLOR
:
1197 return VgaCrtcIndex
;
1199 case VGA_CRTC_DATA_MONO
:
1200 case VGA_CRTC_DATA_COLOR
:
1201 return VgaCrtcRegisters
[VgaCrtcIndex
];
1207 return VgaGcRegisters
[VgaGcIndex
];
1210 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1217 VOID WINAPI
VgaWritePort(ULONG Port
, BYTE Data
)
1219 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1223 case VGA_MISC_WRITE
:
1225 VgaMiscRegister
= Data
;
1227 if (VgaMiscRegister
& 0x01)
1229 /* Color emulation */
1230 DPRINT1("Color emulation\n");
1232 /* Register the new I/O Ports */
1233 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1234 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1235 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1237 /* Unregister the old ones */
1238 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1239 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1240 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1244 /* Monochrome emulation */
1245 DPRINT1("Monochrome emulation\n");
1247 /* Register the new I/O Ports */
1248 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1249 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1250 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1252 /* Unregister the old ones */
1253 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1254 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1255 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1258 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1262 case VGA_FEATURE_WRITE_MONO
:
1263 case VGA_FEATURE_WRITE_COLOR
:
1265 VgaFeatureRegister
= Data
;
1270 // case VGA_AC_WRITE:
1274 /* Change the index */
1275 if (Data
< VGA_AC_MAX_REG
) VgaAcIndex
= Data
;
1279 /* Write the data */
1283 /* Toggle the latch */
1284 VgaAcLatch
= !VgaAcLatch
;
1290 /* Set the sequencer index register */
1291 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
1297 /* Call the sequencer function */
1298 VgaWriteSequencer(Data
);
1308 case VGA_DAC_READ_INDEX
:
1310 VgaDacReadWrite
= FALSE
;
1311 VgaDacIndex
= Data
* 3;
1315 case VGA_DAC_WRITE_INDEX
:
1317 VgaDacReadWrite
= TRUE
;
1318 VgaDacIndex
= Data
* 3;
1324 /* Ignore writes in read mode */
1325 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1329 case VGA_CRTC_INDEX_MONO
:
1330 case VGA_CRTC_INDEX_COLOR
:
1332 /* Set the CRTC index register */
1333 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
1337 case VGA_CRTC_DATA_MONO
:
1338 case VGA_CRTC_DATA_COLOR
:
1340 /* Call the CRTC function */
1347 /* Set the GC index register */
1348 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
1354 /* Call the GC function */
1360 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port
);
1365 VOID
VgaClearMemory(VOID
)
1367 ZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1370 VOID
VgaResetPalette(VOID
)
1372 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
1374 /* Restore the default palette */
1375 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
1377 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
1378 PaletteChanged
= TRUE
;
1381 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
1387 COORD Origin
= { 0, 0 };
1388 SMALL_RECT ScreenRect
;
1389 PCHAR_INFO CharBuffer
;
1393 /* Initialize the VGA palette and fail if it isn't successfully created */
1394 if (!VgaInitializePalette()) return FALSE
;
1396 /* Set the global handle */
1397 TextConsoleBuffer
= TextHandle
;
1399 /* Register the I/O Ports */
1400 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
1401 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
1402 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
1403 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
1404 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
1405 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
1406 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
1407 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
1408 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
1409 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
1410 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
1411 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
1412 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
1414 /* Clear the VGA memory */
1417 /* Set the default video mode */
1418 BiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE
);
1422 Resolution
= VgaGetDisplayResolution();
1423 CharBuffer
= (PCHAR_INFO
)ConsoleFramebuffer
;
1424 AddressSize
= VgaGetAddressSize();
1425 ScreenRect
.Left
= ScreenRect
.Top
= 0;
1426 ScreenRect
.Right
= Resolution
.X
;
1427 ScreenRect
.Bottom
= Resolution
.Y
;
1428 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1430 /* Read the data from the console into the framebuffer */
1431 ReadConsoleOutputA(TextConsoleBuffer
,
1437 /* Loop through the scanlines */
1438 for (i
= 0; i
< Resolution
.Y
; i
++)
1440 /* Loop through the characters */
1441 for (j
= 0; j
< Resolution
.X
; j
++)
1443 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1445 /* Store the character in plane 0 */
1446 VgaMemory
[CurrentAddr
] = CharBuffer
[i
* Resolution
.X
+ j
].Char
.AsciiChar
;
1448 /* Store the attribute in plane 1 */
1449 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuffer
[i
* Resolution
.X
+ j
].Attributes
;
1452 /* Move to the next scanline */
1453 Address
+= ScanlineSize
;
1456 /* Return success */