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 *******************************************************************/
15 #include <bios/vidbios.h>
21 /* PRIVATE VARIABLES **********************************************************/
23 static CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
24 static CONST DWORD MemoryLimit
[] = { 0xAFFFF, 0xAFFFF, 0xB7FFF, 0xBFFFF };
27 * Activate this line if you want to use the real
28 * RegisterConsoleVDM API of ReactOS/Windows.
30 // #define USE_REAL_REGISTERCONSOLEVDM
32 #define USE_REACTOS_COLORS
33 // #define USE_DOSBOX_COLORS
35 #if defined(USE_REACTOS_COLORS)
38 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
40 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
41 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
42 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
43 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
44 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
45 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
46 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
47 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
48 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
49 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
50 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
51 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
52 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
53 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
54 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
55 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
56 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
57 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
58 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
59 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
60 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
61 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
62 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
63 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
64 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
65 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
66 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
67 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
68 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
69 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
70 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
71 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
72 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
73 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
74 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
75 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
76 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
77 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
78 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
79 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
80 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
81 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
82 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
83 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
84 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
85 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
86 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
87 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
88 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
89 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
90 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
91 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
92 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
93 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
94 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
95 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
96 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
97 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
98 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
99 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
100 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
101 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
102 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
103 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
106 #elif defined(USE_DOSBOX_COLORS)
109 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
111 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
112 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
113 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
114 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
115 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
116 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
117 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
118 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
119 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
120 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
121 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
122 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
123 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
124 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
125 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
126 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
128 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
129 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
130 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
131 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
132 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
133 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
134 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
135 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
136 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
137 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
138 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
139 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
140 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
141 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
142 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
143 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
145 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
146 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
147 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
148 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
149 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
150 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
151 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
152 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
153 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
154 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
155 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
156 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
157 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
158 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
159 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
160 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
162 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
163 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
164 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
165 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
166 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
167 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
168 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
169 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
170 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
171 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
172 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
173 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
174 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
175 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
176 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
177 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
183 * Default 16-color palette for foreground and background
184 * (corresponding flags in comments).
185 * Taken from subsystems/win32/winsrv/consrv/frontends/gui/conwnd.c
187 static const COLORREF ConsoleColors
[16] =
189 RGB(0, 0, 0), // (Black)
190 RGB(0, 0, 128), // BLUE
191 RGB(0, 128, 0), // GREEN
192 RGB(0, 128, 128), // BLUE | GREEN
193 RGB(128, 0, 0), // RED
194 RGB(128, 0, 128), // BLUE | RED
195 RGB(128, 128, 0), // GREEN | RED
196 RGB(192, 192, 192), // BLUE | GREEN | RED
198 RGB(128, 128, 128), // (Grey) INTENSITY
199 RGB(0, 0, 255), // BLUE | INTENSITY
200 RGB(0, 255, 0), // GREEN | INTENSITY
201 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
202 RGB(255, 0, 0), // RED | INTENSITY
203 RGB(255, 0, 255), // BLUE | RED | INTENSITY
204 RGB(255, 255, 0), // GREEN | RED | INTENSITY
205 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
209 * Console interface -- VGA-mode-agnostic
211 typedef struct _CHAR_CELL
215 } CHAR_CELL
, *PCHAR_CELL
;
216 C_ASSERT(sizeof(CHAR_CELL
) == 2);
218 static LPVOID ConsoleFramebuffer
= NULL
; // Active framebuffer, points to
219 // either TextFramebuffer or a
220 // valid graphics framebuffer.
221 static HPALETTE TextPaletteHandle
= NULL
;
222 static HPALETTE PaletteHandle
= NULL
;
224 static HANDLE StartEvent
= NULL
;
225 static HANDLE EndEvent
= NULL
;
226 static HANDLE AnotherEvent
= NULL
;
228 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo
;
229 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo
;
233 * Text mode -- we always keep a valid text mode framebuffer
234 * even if we are in graphics mode. This is needed in order
235 * to keep a consistent VGA state.
237 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
238 static COORD TextResolution
= {0};
239 static PCHAR_CELL TextFramebuffer
= NULL
;
240 static HANDLE TextConsoleBuffer
= NULL
;
243 static HANDLE GraphicsConsoleBuffer
= NULL
;
244 static HANDLE ConsoleMutex
= NULL
;
245 /* DoubleVision support */
246 static BOOLEAN DoubleWidth
= FALSE
;
247 static BOOLEAN DoubleHeight
= FALSE
;
249 static PHARDWARE_TIMER VSyncTimer
;
250 static PHARDWARE_TIMER HSyncTimer
;
255 static BYTE VgaMemory
[VGA_NUM_BANKS
* VGA_BANK_SIZE
];
257 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
259 static BYTE VgaMiscRegister
;
260 static BYTE VgaFeatureRegister
;
262 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
263 static BYTE VgaSeqRegisters
[VGA_SEQ_MAX_REG
];
265 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
266 static BYTE VgaCrtcRegisters
[VGA_CRTC_MAX_REG
];
268 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
269 static BYTE VgaGcRegisters
[VGA_GC_MAX_REG
];
271 static BOOLEAN VgaAcLatch
= FALSE
;
272 static BOOLEAN VgaAcPalDisable
= TRUE
;
273 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
274 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
276 static BYTE VgaDacMask
= 0xFF;
278 static BOOLEAN VgaDacReadWrite
= FALSE
;
279 static WORD VgaDacIndex
= 0;
280 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
282 // static VGA_REGISTERS VgaRegisters;
284 static BOOLEAN InVerticalRetrace
= FALSE
;
285 static BOOLEAN InHorizontalRetrace
= FALSE
;
287 static BOOLEAN NeedsUpdate
= FALSE
;
288 static BOOLEAN ModeChanged
= FALSE
;
289 static BOOLEAN CursorChanged
= FALSE
;
290 static BOOLEAN PaletteChanged
= FALSE
;
292 typedef enum _SCREEN_MODE
296 } SCREEN_MODE
, *PSCREEN_MODE
;
298 static SCREEN_MODE ScreenMode
= TEXT_MODE
;
299 static COORD CurrResolution
= {0};
301 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
303 /* RegisterConsoleVDM EMULATION ***********************************************/
305 #include <ntddvdeo.h>
307 #ifdef USE_REAL_REGISTERCONSOLEVDM
309 #define __RegisterConsoleVDM RegisterConsoleVDM
310 #define __InvalidateConsoleDIBits InvalidateConsoleDIBits
315 * This private buffer, per-console, is used by
316 * RegisterConsoleVDM and InvalidateConsoleDIBits.
318 static COORD VDMBufferSize
= {0};
319 static PCHAR_CELL VDMBuffer
= NULL
;
321 static PCHAR_INFO CharBuff
= NULL
; // This is a hack, which is unneeded
322 // for the real RegisterConsoleVDM and
323 // InvalidateConsoleDIBits
327 __RegisterConsoleVDM(IN DWORD dwRegisterFlags
,
328 IN HANDLE hStartHardwareEvent
,
329 IN HANDLE hEndHardwareEvent
,
330 IN HANDLE hErrorHardwareEvent
,
331 IN DWORD dwUnusedVar
,
332 OUT LPDWORD lpVideoStateLength
,
333 OUT PVOID
* lpVideoState
, // PVIDEO_HARDWARE_STATE_HEADER*
334 IN PVOID lpUnusedBuffer
,
335 IN DWORD dwUnusedBufferLength
,
336 IN COORD dwVDMBufferSize
,
337 OUT PVOID
* lpVDMBuffer
)
339 UNREFERENCED_PARAMETER(hErrorHardwareEvent
);
340 UNREFERENCED_PARAMETER(dwUnusedVar
);
341 UNREFERENCED_PARAMETER(lpVideoStateLength
);
342 UNREFERENCED_PARAMETER(lpVideoState
);
343 UNREFERENCED_PARAMETER(lpUnusedBuffer
);
344 UNREFERENCED_PARAMETER(dwUnusedBufferLength
);
347 DPRINT1("__RegisterConsoleVDM(%d)\n", dwRegisterFlags
);
349 if (lpVDMBuffer
== NULL
) return FALSE
;
351 if (dwRegisterFlags
!= 0)
353 // if (hStartHardwareEvent == NULL || hEndHardwareEvent == NULL) return FALSE;
354 if (VDMBuffer
!= NULL
) return FALSE
;
356 VDMBufferSize
= dwVDMBufferSize
;
358 /* HACK: Cache -- to be removed in the real implementation */
359 CharBuff
= HeapAlloc(GetProcessHeap(),
361 VDMBufferSize
.X
* VDMBufferSize
.Y
362 * sizeof(CHAR_INFO
));
365 VDMBuffer
= HeapAlloc(GetProcessHeap(),
367 VDMBufferSize
.X
* VDMBufferSize
.Y
368 * sizeof(CHAR_CELL
));
369 *lpVDMBuffer
= VDMBuffer
;
370 return (VDMBuffer
!= NULL
);
374 /* HACK: Cache -- to be removed in the real implementation */
375 if (CharBuff
) HeapFree(GetProcessHeap(), 0, CharBuff
);
378 if (VDMBuffer
) HeapFree(GetProcessHeap(), 0, VDMBuffer
);
381 VDMBufferSize
.X
= VDMBufferSize
.Y
= 0;
388 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput
,
389 IN PSMALL_RECT lpRect
)
391 if ((hConsoleOutput
== TextConsoleBuffer
) && (VDMBuffer
!= NULL
))
393 /* HACK: Write the cached data to the console */
395 COORD Origin
= { lpRect
->Left
, lpRect
->Top
};
400 for (i
= 0; i
< VDMBufferSize
.Y
; i
++)
402 for (j
= 0; j
< VDMBufferSize
.X
; j
++)
404 CharBuff
[i
* VDMBufferSize
.X
+ j
].Char
.AsciiChar
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Char
;
405 CharBuff
[i
* VDMBufferSize
.X
+ j
].Attributes
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Attributes
;
409 WriteConsoleOutputA(hConsoleOutput
,
416 return InvalidateConsoleDIBits(hConsoleOutput
, lpRect
);
421 /* PRIVATE FUNCTIONS **********************************************************/
423 static inline DWORD
VgaGetAddressSize(VOID
);
424 static VOID
VgaUpdateTextCursor(VOID
);
426 static inline DWORD
VgaGetVideoBaseAddress(VOID
)
428 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
431 static inline DWORD
VgaGetVideoLimitAddress(VOID
)
433 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
436 static VOID
VgaUpdateCursorPosition(VOID
)
439 * Update the cursor position in the VGA registers.
441 WORD Offset
= ConsoleInfo
.dwCursorPosition
.Y
* TextResolution
.X
+
442 ConsoleInfo
.dwCursorPosition
.X
;
444 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
] = LOBYTE(Offset
);
445 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
] = HIBYTE(Offset
);
447 // VidBiosSyncCursorPosition();
448 VgaUpdateTextCursor();
451 static BOOL
VgaAttachToConsoleInternal(PCOORD Resolution
)
455 PVIDEO_HARDWARE_STATE_HEADER State
;
457 #ifdef USE_REAL_REGISTERCONSOLEVDM
458 PCHAR_INFO CharBuff
= NULL
;
461 DWORD AddressSize
, ScanlineSize
;
465 COORD Origin
= { 0, 0 };
467 ASSERT(TextFramebuffer
== NULL
);
469 TextResolution
= *Resolution
;
472 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
473 * in the two following APIs:
474 * SrvRegisterConsoleVDM (corresponding Win32 API: RegisterConsoleVDM)
475 * SrvVDMConsoleOperation (corresponding Win32 API: )
476 * to check whether the current process is a VDM process, and fails otherwise
477 * with the error 0xC0000022 (STATUS_ACCESS_DENIED).
479 * It is worth it to notice that also basesrv.dll does the same only for the
480 * BaseSrvIsFirstVDM API...
484 __RegisterConsoleVDM(1,
487 AnotherEvent
, // NULL,
489 &Length
, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
490 (PVOID
*)&State
, // NULL,
494 (PVOID
*)&TextFramebuffer
);
497 DisplayMessage(L
"RegisterConsoleVDM failed with error %d\n", GetLastError());
502 #ifdef USE_REAL_REGISTERCONSOLEVDM
503 CharBuff
= HeapAlloc(GetProcessHeap(),
505 TextResolution
.X
* TextResolution
.Y
506 * sizeof(CHAR_INFO
));
514 ConRect
.Top
= ConsoleInfo
.srWindow
.Top
;
515 ConRect
.Right
= ConRect
.Left
+ Resolution
->X
- 1;
516 ConRect
.Bottom
= ConRect
.Top
+ Resolution
->Y
- 1;
518 * Use this trick to effectively resize the console buffer and window,
520 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
521 * is smaller than the current console window size, and:
522 * - SetConsoleWindowInfo fails if the new console window size is larger
523 * than the current console screen buffer size.
525 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
526 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
527 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
528 /* Update the saved console information */
529 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
532 * Copy console data into VGA memory
536 AddressSize
= VgaGetAddressSize();
537 ConRect
.Left
= ConRect
.Top
= 0;
538 ConRect
.Right
= TextResolution
.X
;
539 ConRect
.Bottom
= TextResolution
.Y
;
540 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
542 /* Read the data from the console into the framebuffer... */
543 ReadConsoleOutputA(TextConsoleBuffer
,
549 /* ... and copy the framebuffer into the VGA memory */
551 /* Loop through the scanlines */
552 for (i
= 0; i
< TextResolution
.Y
; i
++)
554 /* Loop through the characters */
555 for (j
= 0; j
< TextResolution
.X
; j
++)
557 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
559 /* Store the character in plane 0 */
560 VgaMemory
[CurrentAddr
] = CharBuff
[i
* TextResolution
.X
+ j
].Char
.AsciiChar
;
562 /* Store the attribute in plane 1 */
563 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuff
[i
* TextResolution
.X
+ j
].Attributes
;
566 /* Move to the next scanline */
567 Address
+= ScanlineSize
;
570 #ifdef USE_REAL_REGISTERCONSOLEVDM
571 if (CharBuff
) HeapFree(GetProcessHeap(), 0, CharBuff
);
574 VgaUpdateCursorPosition();
579 static BOOL
IsConsoleHandle(HANDLE hHandle
)
583 /* Check whether the handle may be that of a console... */
584 if ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) != FILE_TYPE_CHAR
)
588 * It may be. Perform another test... The idea comes from the
589 * MSDN description of the WriteConsole API:
591 * "WriteConsole fails if it is used with a standard handle
592 * that is redirected to a file. If an application processes
593 * multilingual output that can be redirected, determine whether
594 * the output handle is a console handle (one method is to call
595 * the GetConsoleMode function and check whether it succeeds).
596 * If the handle is a console handle, call WriteConsole. If the
597 * handle is not a console handle, the output is redirected and
598 * you should call WriteFile to perform the I/O."
600 return GetConsoleMode(hHandle
, &dwMode
);
603 static inline DWORD
VgaGetAddressSize(VOID
)
605 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
607 /* Double-word addressing */
608 return 4; // sizeof(DWORD)
610 else if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
612 /* Byte addressing */
613 return 1; // sizeof(BYTE)
617 /* Word addressing */
618 return 2; // sizeof(WORD)
622 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
624 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
627 /* Check for chain-4 and odd-even mode */
628 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
630 /* The lowest two bits are the plane number */
631 Plane
= Offset
& 0x03;
634 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
636 /* The LSB is the plane number */
637 Plane
= Offset
& 0x01;
642 /* Use the read mode */
643 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
646 /* Multiply the offset by the address size */
647 Offset
*= VgaGetAddressSize();
649 return Offset
+ Plane
* VGA_BANK_SIZE
;
652 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
654 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
656 /* Check for chain-4 and odd-even mode */
657 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
659 /* Shift the offset to the right by 2 */
662 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
664 /* Shift the offset to the right by 1 */
668 /* Multiply the offset by the address size */
669 Offset
*= VgaGetAddressSize();
671 /* Return the offset on plane 0 */
675 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
677 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 0x03;
678 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
682 /* In write mode 1 just return the latch register */
683 return VgaLatchRegisters
[Plane
];
688 /* Write modes 0 and 3 rotate the data to the right first */
689 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 0x07;
690 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
694 /* Write mode 2 expands the appropriate bit to all 8 bits */
695 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
701 * In write mode 0, the enable set/reset register decides if the
702 * set/reset bit should be expanded to all 8 bits.
704 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
706 /* Copy the bit from the set/reset register to all 8 bits */
707 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
713 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
714 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 0x03;
716 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
717 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
718 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
722 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
725 /* Then we expand the bit in the set/reset field */
726 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
729 /* Bits cleared in the bitmask are replaced with latch register bits */
730 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
732 /* Return the byte */
736 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
738 /* Check if this is the first time the rectangle is updated */
741 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
742 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
745 /* Expand the rectangle to include the point */
746 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
747 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
748 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
749 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
751 /* Set the update request flag */
755 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
759 /* Copy the colors of the default palette to the DAC and console palette */
760 for (i
= 0; i
< NumOfEntries
; i
++)
762 /* Set the palette entries */
763 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
764 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
765 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
766 Entries
[i
].peFlags
= 0;
768 /* Set the DAC registers */
769 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
770 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
771 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
775 static BOOLEAN
VgaInitializePalette(VOID
)
778 BOOLEAN Result
= FALSE
;
779 LPLOGPALETTE Palette
, TextPalette
;
781 /* Allocate storage space for the palettes */
782 Palette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
785 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
786 TextPalette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
789 (VGA_AC_PAL_F_REG
+ 1) * sizeof(PALETTEENTRY
));
790 if ((Palette
== NULL
) || (TextPalette
== NULL
)) goto Cleanup
;
792 /* Initialize the palettes */
793 Palette
->palVersion
= TextPalette
->palVersion
= 0x0300;
794 Palette
->palNumEntries
= VGA_MAX_COLORS
;
795 TextPalette
->palNumEntries
= VGA_AC_PAL_F_REG
+ 1;
797 /* Restore the default graphics palette */
798 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
800 /* Set the default text palette */
801 for (i
= 0; i
< TextPalette
->palNumEntries
; i
++)
803 /* Set the palette entries */
804 TextPalette
->palPalEntry
[i
].peRed
= GetRValue(ConsoleColors
[i
]);
805 TextPalette
->palPalEntry
[i
].peGreen
= GetGValue(ConsoleColors
[i
]);
806 TextPalette
->palPalEntry
[i
].peBlue
= GetBValue(ConsoleColors
[i
]);
807 TextPalette
->palPalEntry
[i
].peFlags
= 0;
810 /* Create the palettes */
811 PaletteHandle
= CreatePalette(Palette
);
812 TextPaletteHandle
= CreatePalette(TextPalette
);
814 if (PaletteHandle
!= NULL
&& TextPaletteHandle
!= NULL
)
816 /* The palettes have been created successfully */
821 /* Free the palettes */
822 if (Palette
) HeapFree(GetProcessHeap(), 0, Palette
);
823 if (TextPalette
) HeapFree(GetProcessHeap(), 0, TextPalette
);
827 /* Something failed, delete the palettes */
828 if (PaletteHandle
) DeleteObject(PaletteHandle
);
829 if (TextPaletteHandle
) DeleteObject(TextPaletteHandle
);
835 static VOID
VgaResetPalette(VOID
)
837 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
839 /* Restore the default palette */
840 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
841 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
842 PaletteChanged
= TRUE
;
845 static VOID
VgaSetActiveScreenBuffer(HANDLE ScreenBuffer
)
847 /* Set the active buffer */
848 SetConsoleActiveScreenBuffer(ScreenBuffer
);
850 /* Reinitialize the VDM menu */
852 CreateVdmMenu(ScreenBuffer
);
855 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
858 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
859 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
860 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
861 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
863 LONG Width
= Resolution
->X
;
864 LONG Height
= Resolution
->Y
;
866 /* Use DoubleVision mode if the resolution is too small */
867 DoubleWidth
= (Width
< VGA_MINIMUM_WIDTH
);
868 if (DoubleWidth
) Width
*= 2;
869 DoubleHeight
= (Height
< VGA_MINIMUM_HEIGHT
);
870 if (DoubleHeight
) Height
*= 2;
872 /* Fill the bitmap info header */
873 RtlZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BitmapInfo
->bmiHeader
));
874 BitmapInfo
->bmiHeader
.biSize
= sizeof(BitmapInfo
->bmiHeader
);
875 BitmapInfo
->bmiHeader
.biWidth
= Width
;
876 BitmapInfo
->bmiHeader
.biHeight
= Height
;
877 BitmapInfo
->bmiHeader
.biBitCount
= 8;
878 BitmapInfo
->bmiHeader
.biPlanes
= 1;
879 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
880 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
882 /* Fill the palette data */
883 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
885 /* Fill the console graphics buffer info */
886 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
887 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
888 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
890 /* Create the buffer */
891 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
892 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
894 CONSOLE_GRAPHICS_BUFFER
,
895 &GraphicsBufferInfo
);
896 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
898 /* Save the framebuffer address and mutex */
899 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
900 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
902 /* Clear the framebuffer */
903 RtlZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
905 /* Set the active buffer */
906 VgaSetActiveScreenBuffer(GraphicsConsoleBuffer
);
908 /* Set the graphics mode palette */
909 SetConsolePalette(GraphicsConsoleBuffer
,
913 /* Set the screen mode flag */
914 ScreenMode
= GRAPHICS_MODE
;
919 static VOID
VgaLeaveGraphicsMode(VOID
)
921 /* Release the console framebuffer mutex */
922 ReleaseMutex(ConsoleMutex
);
924 /* Switch back to the default console text buffer */
925 // VgaSetActiveScreenBuffer(TextConsoleBuffer);
927 /* Cleanup the video data */
928 CloseHandle(ConsoleMutex
);
930 ConsoleFramebuffer
= NULL
;
931 CloseHandle(GraphicsConsoleBuffer
);
932 GraphicsConsoleBuffer
= NULL
;
935 DoubleHeight
= FALSE
;
938 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
940 /* Switch to the text buffer */
941 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
943 /* Adjust the text framebuffer if we changed the resolution */
944 if (TextResolution
.X
!= Resolution
->X
||
945 TextResolution
.Y
!= Resolution
->Y
)
947 VgaDetachFromConsole(TRUE
);
950 * VgaAttachToConsoleInternal sets TextResolution to the
951 * new resolution and updates ConsoleInfo.
953 if (!VgaAttachToConsoleInternal(Resolution
))
955 DisplayMessage(L
"An unexpected error occurred!\n");
962 VgaUpdateCursorPosition();
965 /* The active framebuffer is now the text framebuffer */
966 ConsoleFramebuffer
= TextFramebuffer
;
969 * Set the text mode palette.
971 * WARNING: This call should fail on Windows (and therefore
972 * we get the default palette and our external behaviour is
973 * just like Windows' one), but it should success on ReactOS
974 * (so that we get console palette changes even for text-mode
975 * screen-buffers, which is a new feature on ReactOS).
977 SetConsolePalette(TextConsoleBuffer
,
981 /* Set the screen mode flag */
982 ScreenMode
= TEXT_MODE
;
987 static VOID
VgaLeaveTextMode(VOID
)
989 /* Reset the active framebuffer */
990 ConsoleFramebuffer
= NULL
;
993 static VOID
VgaChangeMode(VOID
)
995 COORD NewResolution
= VgaGetDisplayResolution();
996 SCREEN_MODE NewScreenMode
=
997 !(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) ? TEXT_MODE
1001 * No need to switch to a different screen mode + resolution
1002 * if the new ones are the same as the old ones.
1004 if ((ScreenMode
== NewScreenMode
) &&
1005 (CurrResolution
.X
== NewResolution
.X
&& CurrResolution
.Y
== NewResolution
.Y
))
1010 if (ScreenMode
== GRAPHICS_MODE
)
1012 /* Leave the current graphics mode */
1013 VgaLeaveGraphicsMode();
1017 /* Leave the current text mode */
1021 /* Update the current resolution */
1022 CurrResolution
= NewResolution
;
1024 /* The new screen mode will be updated via the VgaEnterText/GraphicsMode functions */
1026 /* Check if the new mode is alphanumeric */
1027 if (NewScreenMode
== TEXT_MODE
)
1029 /* Enter new text mode */
1030 if (!VgaEnterTextMode(&CurrResolution
))
1032 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
1033 EmulatorTerminate();
1039 /* Enter graphics mode */
1040 if (!VgaEnterGraphicsMode(&CurrResolution
))
1042 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
1043 EmulatorTerminate();
1050 /* Trigger a full update of the screen */
1052 UpdateRectangle
.Left
= 0;
1053 UpdateRectangle
.Top
= 0;
1054 UpdateRectangle
.Right
= CurrResolution
.X
;
1055 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
1057 /* Reset the mode change flag */
1058 ModeChanged
= FALSE
;
1061 static VOID
VgaUpdateFramebuffer(VOID
)
1064 DWORD AddressSize
= VgaGetAddressSize();
1065 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
1066 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
]);
1067 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1070 * If console framebuffer is NULL, that means something went wrong
1071 * earlier and this is the final display refresh.
1073 if (ConsoleFramebuffer
== NULL
) return;
1075 /* Check if we are in text or graphics mode */
1076 if (ScreenMode
== GRAPHICS_MODE
)
1079 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
1080 DWORD InterlaceHighBit
= VGA_INTERLACE_HIGH_BIT
;
1083 * Synchronize access to the graphics framebuffer
1084 * with the console framebuffer mutex.
1086 WaitForSingleObject(ConsoleMutex
, INFINITE
);
1088 /* Shift the high bit right by 1 in odd/even mode */
1089 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1091 InterlaceHighBit
>>= 1;
1094 /* Loop through the scanlines */
1095 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1097 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1099 /* Odd-numbered line in interlaced mode - set the high bit */
1100 Address
|= InterlaceHighBit
;
1103 /* Loop through the pixels */
1104 for (j
= 0; j
< CurrResolution
.X
; j
++)
1108 /* Check the shifting mode */
1109 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
1111 /* 4 bits shifted from each plane */
1113 /* Check if this is 16 or 256 color mode */
1114 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1116 /* One byte per pixel */
1117 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1118 + LOWORD((Address
+ (j
/ VGA_NUM_BANKS
))
1123 /* 4-bits per pixel */
1125 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1126 + LOWORD((Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1129 /* Check if we should use the highest 4 bits or lowest 4 */
1130 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
1142 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
1144 /* Check if this is 16 or 256 color mode */
1145 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1147 // TODO: NOT IMPLEMENTED
1148 DPRINT1("8-bit interleaved mode is not implemented!\n");
1153 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1154 * then 2 bits shifted from plane 1 and 3 for the next 4
1156 DWORD BankNumber
= (j
/ 4) % 2;
1157 DWORD Offset
= Address
+ (j
/ 8);
1158 BYTE LowPlaneData
= VgaMemory
[BankNumber
* VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
1159 BYTE HighPlaneData
= VgaMemory
[(BankNumber
+ 2) * VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
1161 /* Extract the two bits from each plane */
1162 LowPlaneData
= (LowPlaneData
>> (6 - ((j
% 4) * 2))) & 0x03;
1163 HighPlaneData
= (HighPlaneData
>> (6 - ((j
% 4) * 2))) & 0x03;
1165 /* Combine them into the pixel */
1166 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
1171 /* 1 bit shifted from each plane */
1173 /* Check if this is 16 or 256 color mode */
1174 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1176 /* 8 bits per pixel, 2 on each plane */
1178 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1180 /* The data is on plane k, 4 pixels per byte */
1181 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1182 + LOWORD((Address
+ (j
/ VGA_NUM_BANKS
))
1185 /* The mask of the first bit in the pair */
1186 BYTE BitMask
= 1 << (((3 - (j
% VGA_NUM_BANKS
)) * 2) + 1);
1188 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1189 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
1191 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1192 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
1197 /* 4 bits per pixel, 1 on each plane */
1199 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1201 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1202 + LOWORD((Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1205 /* If the bit on that plane is set, set it */
1206 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
1211 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
1214 * In 16 color mode, the value is an index to the AC registers
1215 * if external palette access is disabled, otherwise (in case
1216 * of palette loading) it is a blank pixel.
1218 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
1222 /* Take into account DoubleVision mode when checking for pixel updates */
1223 if (DoubleWidth
&& DoubleHeight
)
1225 /* Now check if the resulting pixel data has changed */
1226 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
1228 /* Yes, write the new value */
1229 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1230 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1231 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1232 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1234 /* Mark the specified pixel as changed */
1235 VgaMarkForUpdate(i
, j
);
1238 else if (DoubleWidth
&& !DoubleHeight
)
1240 /* Now check if the resulting pixel data has changed */
1241 if (GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
1243 /* Yes, write the new value */
1244 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1245 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1247 /* Mark the specified pixel as changed */
1248 VgaMarkForUpdate(i
, j
);
1251 else if (!DoubleWidth
&& DoubleHeight
)
1253 /* Now check if the resulting pixel data has changed */
1254 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] != PixelData
)
1256 /* Yes, write the new value */
1257 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] = PixelData
;
1258 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
) + j
] = PixelData
;
1260 /* Mark the specified pixel as changed */
1261 VgaMarkForUpdate(i
, j
);
1264 else // if (!DoubleWidth && !DoubleHeight)
1266 /* Now check if the resulting pixel data has changed */
1267 if (GraphicsBuffer
[i
* CurrResolution
.X
+ j
] != PixelData
)
1269 /* Yes, write the new value */
1270 GraphicsBuffer
[i
* CurrResolution
.X
+ j
] = PixelData
;
1272 /* Mark the specified pixel as changed */
1273 VgaMarkForUpdate(i
, j
);
1278 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1280 /* Clear the high bit */
1281 Address
&= ~InterlaceHighBit
;
1284 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) || (i
& 1))
1286 /* Move to the next scanline */
1287 Address
+= ScanlineSize
;
1292 * Release the console framebuffer mutex
1293 * so that we allow for repainting.
1295 ReleaseMutex(ConsoleMutex
);
1301 PCHAR_CELL CharBuffer
= (PCHAR_CELL
)ConsoleFramebuffer
;
1304 /* Loop through the scanlines */
1305 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1307 /* Loop through the characters */
1308 for (j
= 0; j
< CurrResolution
.X
; j
++)
1310 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1312 /* Plane 0 holds the character itself */
1313 CharInfo
.Char
= VgaMemory
[CurrentAddr
];
1315 /* Plane 1 holds the attribute */
1316 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
1318 /* Now check if the resulting character data has changed */
1319 if ((CharBuffer
[i
* CurrResolution
.X
+ j
].Char
!= CharInfo
.Char
) ||
1320 (CharBuffer
[i
* CurrResolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
1322 /* Yes, write the new value */
1323 CharBuffer
[i
* CurrResolution
.X
+ j
] = CharInfo
;
1325 /* Mark the specified cell as changed */
1326 VgaMarkForUpdate(i
, j
);
1330 /* Move to the next scanline */
1331 Address
+= ScanlineSize
;
1336 static VOID
VgaUpdateTextCursor(VOID
)
1339 CONSOLE_CURSOR_INFO CursorInfo
;
1341 BOOL CursorVisible
= !(VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x20);
1342 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x1F;
1343 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
1345 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1346 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1347 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
1348 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
1350 /* Just return if we are not in text mode */
1351 if (ScreenMode
!= TEXT_MODE
) return;
1353 if (CursorStart
< CursorEnd
)
1355 /* Visible cursor */
1356 CursorInfo
.bVisible
= CursorVisible
;
1357 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
1362 CursorInfo
.bVisible
= FALSE
;
1363 CursorInfo
.dwSize
= 1; // The size needs to be non-null in order SetConsoleCursorInfo to succeed.
1366 /* Add the cursor skew to the location */
1367 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 0x03;
1369 /* Find the coordinates of the new position */
1370 Position
.X
= (SHORT
)(Location
% ScanlineSize
);
1371 Position
.Y
= (SHORT
)(Location
/ ScanlineSize
);
1373 DPRINT("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position
.X
, Position
.Y
);
1375 /* Update the physical cursor */
1376 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
1377 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
1379 /* Reset the cursor changed flag */
1380 CursorChanged
= FALSE
;
1383 static BYTE WINAPI
VgaReadPort(USHORT Port
)
1385 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1390 return VgaMiscRegister
;
1392 case VGA_INSTAT0_READ
:
1393 return 0; // Not implemented
1395 case VGA_INSTAT1_READ_MONO
:
1396 case VGA_INSTAT1_READ_COLOR
:
1400 /* Reset the AC latch */
1403 /* Set a flag if there is a vertical or horizontal retrace */
1404 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
1406 /* Set an additional flag if there was a vertical retrace */
1407 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
1409 /* Clear the flags */
1410 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
1415 case VGA_FEATURE_READ
:
1416 return VgaFeatureRegister
;
1422 return VgaAcRegisters
[VgaAcIndex
];
1428 return VgaSeqRegisters
[VgaSeqIndex
];
1433 case VGA_DAC_READ_INDEX
:
1434 /* This returns the read/write state */
1435 return (VgaDacReadWrite
? 0 : 3);
1437 case VGA_DAC_WRITE_INDEX
:
1438 return (VgaDacIndex
/ 3);
1442 /* Ignore reads in write mode */
1443 if (!VgaDacReadWrite
)
1445 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
1446 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1453 case VGA_CRTC_INDEX_MONO
:
1454 case VGA_CRTC_INDEX_COLOR
:
1455 return VgaCrtcIndex
;
1457 case VGA_CRTC_DATA_MONO
:
1458 case VGA_CRTC_DATA_COLOR
:
1459 return VgaCrtcRegisters
[VgaCrtcIndex
];
1465 return VgaGcRegisters
[VgaGcIndex
];
1468 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1475 static inline VOID
VgaWriteSequencer(BYTE Data
)
1477 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
1479 /* Save the value */
1480 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
1483 static inline VOID
VgaWriteGc(BYTE Data
)
1485 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
1487 /* Save the value */
1488 VgaGcRegisters
[VgaGcIndex
] = Data
;
1490 /* Check the index */
1493 case VGA_GC_MISC_REG
:
1495 /* The GC misc register decides if it's text or graphics mode */
1502 static inline VOID
VgaWriteCrtc(BYTE Data
)
1504 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
1506 /* Save the value */
1507 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
1509 /* Check the index */
1510 switch (VgaCrtcIndex
)
1512 case VGA_CRTC_END_HORZ_DISP_REG
:
1513 case VGA_CRTC_VERT_DISP_END_REG
:
1514 case VGA_CRTC_OVERFLOW_REG
:
1515 case VGA_CRTC_MAX_SCAN_LINE_REG
:
1517 /* The video mode has changed */
1522 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
1523 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
1524 case VGA_CRTC_CURSOR_START_REG
:
1525 case VGA_CRTC_CURSOR_END_REG
:
1527 /* Set the cursor changed flag */
1528 CursorChanged
= TRUE
;
1534 static inline VOID
VgaWriteDac(BYTE Data
)
1536 INT i
, PaletteIndex
;
1540 VgaDacRegisters
[VgaDacIndex
] = Data
;
1542 /* Find the palette index */
1543 PaletteIndex
= VgaDacIndex
/ 3;
1545 /* Fill the entry structure */
1546 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3]);
1547 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 1]);
1548 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 2]);
1551 /* Update the palette entry */
1552 SetPaletteEntries(PaletteHandle
, PaletteIndex
, 1, &Entry
);
1554 /* Check which text palette entries are affected */
1555 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
1557 if (VgaAcRegisters
[i
] == PaletteIndex
)
1559 /* Update the text palette entry */
1560 SetPaletteEntries(TextPaletteHandle
, i
, 1, &Entry
);
1564 /* Set the palette changed flag */
1565 PaletteChanged
= TRUE
;
1567 /* Update the index */
1569 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1572 static inline VOID
VgaWriteAc(BYTE Data
)
1576 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
1578 /* Save the value */
1579 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
1581 if (VgaAcPalDisable
) return;
1583 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
1584 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
1586 /* Update the AC register */
1587 VgaAcRegisters
[VgaAcIndex
] = Data
;
1589 /* Fill the entry structure */
1590 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3]);
1591 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 1]);
1592 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 2]);
1595 /* Update the palette entry and set the palette change flag */
1596 SetPaletteEntries(TextPaletteHandle
, VgaAcIndex
, 1, &Entry
);
1597 PaletteChanged
= TRUE
;
1602 VgaAcRegisters
[VgaAcIndex
] = Data
;
1606 static VOID WINAPI
VgaWritePort(USHORT Port
, BYTE Data
)
1608 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1612 case VGA_MISC_WRITE
:
1614 VgaMiscRegister
= Data
;
1616 if (VgaMiscRegister
& 0x01)
1618 /* Color emulation */
1619 DPRINT1("Color emulation\n");
1621 /* Register the new I/O Ports */
1622 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1623 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1624 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1626 /* Unregister the old ones */
1627 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1628 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1629 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1633 /* Monochrome emulation */
1634 DPRINT1("Monochrome emulation\n");
1636 /* Register the new I/O Ports */
1637 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1638 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1639 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1641 /* Unregister the old ones */
1642 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1643 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1644 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1647 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1651 case VGA_FEATURE_WRITE_MONO
:
1652 case VGA_FEATURE_WRITE_COLOR
:
1654 VgaFeatureRegister
= Data
;
1659 // case VGA_AC_WRITE:
1663 /* Change the index */
1664 BYTE Index
= Data
& 0x1F;
1665 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1668 * Change palette protection by checking for
1669 * the Palette Address Source bit.
1671 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1675 /* Write the data */
1679 /* Toggle the latch */
1680 VgaAcLatch
= !VgaAcLatch
;
1686 /* Set the sequencer index register */
1687 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
1693 /* Call the sequencer function */
1694 VgaWriteSequencer(Data
);
1704 case VGA_DAC_READ_INDEX
:
1706 VgaDacReadWrite
= FALSE
;
1707 VgaDacIndex
= Data
* 3;
1711 case VGA_DAC_WRITE_INDEX
:
1713 VgaDacReadWrite
= TRUE
;
1714 VgaDacIndex
= Data
* 3;
1720 /* Ignore writes in read mode */
1721 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1725 case VGA_CRTC_INDEX_MONO
:
1726 case VGA_CRTC_INDEX_COLOR
:
1728 /* Set the CRTC index register */
1729 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
1733 case VGA_CRTC_DATA_MONO
:
1734 case VGA_CRTC_DATA_COLOR
:
1736 /* Call the CRTC function */
1743 /* Set the GC index register */
1744 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
1750 /* Call the GC function */
1756 DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port
, Data
);
1761 static VOID FASTCALL
VgaVerticalRetrace(ULONGLONG ElapsedTime
)
1763 HANDLE ConsoleBufferHandle
= NULL
;
1765 UNREFERENCED_PARAMETER(ElapsedTime
);
1767 /* Set the vertical retrace flag */
1768 InVerticalRetrace
= TRUE
;
1770 /* If nothing has changed, just return */
1771 // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
1774 /* Change the display mode */
1775 if (ModeChanged
) VgaChangeMode();
1777 /* Change the text cursor appearance */
1778 if (CursorChanged
) VgaUpdateTextCursor();
1782 /* Trigger a full update of the screen */
1784 UpdateRectangle
.Left
= 0;
1785 UpdateRectangle
.Top
= 0;
1786 UpdateRectangle
.Right
= CurrResolution
.X
;
1787 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
1789 PaletteChanged
= FALSE
;
1792 /* Update the contents of the framebuffer */
1793 VgaUpdateFramebuffer();
1795 /* Ignore if there's nothing to update */
1796 if (!NeedsUpdate
) return;
1798 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1799 UpdateRectangle
.Left
,
1800 UpdateRectangle
.Top
,
1801 UpdateRectangle
.Right
,
1802 UpdateRectangle
.Bottom
);
1804 /* Check if we are in text or graphics mode */
1805 if (ScreenMode
== GRAPHICS_MODE
)
1808 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
1810 /* In DoubleVision mode, scale the update rectangle */
1813 UpdateRectangle
.Left
*= 2;
1814 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
1818 UpdateRectangle
.Top
*= 2;
1819 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
1825 ConsoleBufferHandle
= TextConsoleBuffer
;
1828 /* Redraw the screen */
1829 __InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
1831 /* Clear the update flag */
1832 NeedsUpdate
= FALSE
;
1835 static VOID FASTCALL
VgaHorizontalRetrace(ULONGLONG ElapsedTime
)
1837 UNREFERENCED_PARAMETER(ElapsedTime
);
1840 InHorizontalRetrace
= TRUE
;
1843 /* PUBLIC FUNCTIONS ***********************************************************/
1845 COORD
VgaGetDisplayResolution(VOID
)
1848 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1850 /* The low 8 bits are in the display registers */
1851 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
1852 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
1854 /* Set the top bits from the overflow register */
1855 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
1857 Resolution
.Y
|= 1 << 8;
1859 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
1861 Resolution
.Y
|= 1 << 9;
1864 /* Increase the values by 1 */
1868 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1870 /* Multiply the horizontal resolution by the 9/8 dot mode */
1871 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
1874 /* The horizontal resolution is halved in 8-bit mode */
1875 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
1878 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1880 /* Halve the vertical resolution */
1885 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1886 Resolution
.Y
/= MaximumScanLine
;
1889 /* Return the resolution */
1893 BOOLEAN
VgaGetDoubleVisionState(PBOOLEAN Horizontal
, PBOOLEAN Vertical
)
1895 if (GraphicsConsoleBuffer
== NULL
) return FALSE
;
1896 if (Horizontal
) *Horizontal
= DoubleWidth
;
1897 if (Vertical
) *Vertical
= DoubleHeight
;
1901 VOID
VgaRefreshDisplay(VOID
)
1903 VgaVerticalRetrace(0);
1906 VOID NTAPI
VgaReadMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
1910 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
1912 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1913 Address
= min(max(Address
, VgaGetVideoBaseAddress()), VgaGetVideoLimitAddress());
1914 Size
= min(Size
, VgaGetVideoLimitAddress() - Address
+ 1);
1916 /* Ignore if video RAM access is disabled */
1917 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1919 /* Loop through each byte */
1920 for (i
= 0; i
< Size
; i
++)
1922 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1924 /* Copy the value to the buffer */
1925 BufPtr
[i
] = VgaMemory
[VideoAddress
];
1928 /* Load the latch registers */
1929 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1930 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1931 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1932 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1935 BOOLEAN NTAPI
VgaWriteMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
1939 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
1941 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1942 Address
= min(max(Address
, VgaGetVideoBaseAddress()), VgaGetVideoLimitAddress());
1943 Size
= min(Size
, VgaGetVideoLimitAddress() - Address
+ 1);
1945 /* Ignore if video RAM access is disabled */
1946 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return TRUE
;
1948 /* Also ignore if write access to all planes is disabled */
1949 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return TRUE
;
1951 /* Loop through each byte */
1952 for (i
= 0; i
< Size
; i
++)
1954 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1956 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1958 /* Make sure the page is writeable */
1959 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1961 /* Check if this is chain-4 mode */
1962 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1964 if (((Address
+ i
) & 0x03) != j
)
1966 /* This plane will not be accessed */
1971 /* Check if this is odd-even mode */
1972 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1974 if (((Address
+ i
) & 0x01) != (j
& 1))
1976 /* This plane will not be accessed */
1981 /* Copy the value to the VGA memory */
1982 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(BufPtr
[i
], j
);
1989 VOID
VgaClearMemory(VOID
)
1991 RtlZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1994 VOID
VgaWriteFont(UINT FontNumber
, CONST UCHAR
* FontData
, UINT Height
)
1997 PUCHAR FontMemory
= (PUCHAR
)&VgaMemory
[VGA_BANK_SIZE
* VGA_FONT_BANK
+ (FontNumber
* VGA_FONT_SIZE
)];
1999 ASSERT(Height
<= VGA_MAX_FONT_HEIGHT
);
2001 for (i
= 0 ; i
< VGA_FONT_CHARACTERS
; i
++)
2003 /* Write the character */
2004 for (j
= 0; j
< Height
; j
++)
2006 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = FontData
[i
* Height
+ j
];
2009 /* Clear the unused part */
2010 for (j
= Height
; j
< VGA_MAX_FONT_HEIGHT
; j
++)
2012 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = 0;
2017 VOID
ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent
)
2019 DPRINT1("Screen events not handled\n");
2022 BOOL
VgaAttachToConsole(VOID
)
2025 // FIXME: We should go back to the saved screen state
2027 if (TextResolution
.X
== 0 || TextResolution
.Y
== 0)
2028 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
2030 if (TextResolution
.X
== 0) TextResolution
.X
= 80;
2031 if (TextResolution
.Y
== 0) TextResolution
.Y
= 25;
2033 return VgaAttachToConsoleInternal(&TextResolution
);
2036 VOID
VgaDetachFromConsole(BOOL ChangingMode
)
2040 COORD dummySize
= {0};
2043 // FIXME: We should save the screen state
2046 __RegisterConsoleVDM(0,
2058 TextFramebuffer
= NULL
;
2064 /* Restore the old screen buffer */
2065 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2067 /* Restore the original console size */
2070 ConRect
.Right
= ConRect
.Left
+ OrgConsoleBufferInfo
.srWindow
.Right
- OrgConsoleBufferInfo
.srWindow
.Left
;
2071 ConRect
.Bottom
= ConRect
.Top
+ OrgConsoleBufferInfo
.srWindow
.Bottom
- OrgConsoleBufferInfo
.srWindow
.Top
;
2073 * See the following trick explanation in VgaAttachToConsoleInternal.
2075 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
2076 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
2077 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
2079 /* Restore the original cursor shape */
2080 SetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
);
2084 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
2086 /* Save the default text-mode console output handle */
2087 if (!IsConsoleHandle(TextHandle
)) return FALSE
;
2088 TextConsoleBuffer
= TextHandle
;
2090 /* Save the original cursor and console screen buffer information */
2091 if (!GetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
) ||
2092 !GetConsoleScreenBufferInfo(TextConsoleBuffer
, &OrgConsoleBufferInfo
))
2096 ConsoleInfo
= OrgConsoleBufferInfo
;
2098 /* Initialize the VGA palette and fail if it isn't successfully created */
2099 if (!VgaInitializePalette()) return FALSE
;
2100 /***/ VgaResetPalette(); /***/
2102 /* Switch to the text buffer */
2103 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2105 /* Clear the VGA memory */
2108 /* Register the memory hook */
2109 MemInstallFastMemoryHook((PVOID
)0xA0000, 0x20000, VgaReadMemory
, VgaWriteMemory
);
2111 /* Register the I/O Ports */
2112 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
2113 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
2114 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
2115 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
2116 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
2117 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
2118 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
2119 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
2120 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
2121 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
2122 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
2123 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
2124 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
2126 /* CGA ports for compatibility, unimplemented */
2127 RegisterIoPort(0x3D8, VgaReadPort
, VgaWritePort
); // CGA_MODE_CTRL_REG
2128 RegisterIoPort(0x3D9, VgaReadPort
, VgaWritePort
); // CGA_PAL_CTRL_REG
2130 HSyncTimer
= CreateHardwareTimer(HARDWARE_TIMER_ENABLED
, HZ_TO_NS(31469), VgaHorizontalRetrace
);
2131 VSyncTimer
= CreateHardwareTimer(HARDWARE_TIMER_ENABLED
, HZ_TO_NS(60), VgaVerticalRetrace
);
2133 /* Return success */
2137 VOID
VgaCleanup(VOID
)
2139 DestroyHardwareTimer(VSyncTimer
);
2140 DestroyHardwareTimer(HSyncTimer
);
2142 if (ScreenMode
== GRAPHICS_MODE
)
2144 /* Leave the current graphics mode */
2145 VgaLeaveGraphicsMode();
2149 /* Leave the current text mode */
2153 VgaDetachFromConsole(FALSE
);
2154 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
2156 CloseHandle(AnotherEvent
);
2157 CloseHandle(EndEvent
);
2158 CloseHandle(StartEvent
);