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 *******************************************************************/
16 #include <bios/vidbios.h>
22 /* PRIVATE VARIABLES **********************************************************/
24 static CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
25 static CONST DWORD MemoryLimit
[] = { 0xBFFFF, 0xAFFFF, 0xB7FFF, 0xBFFFF };
28 * Activate this line if you want to use the real
29 * RegisterConsoleVDM API of ReactOS/Windows.
31 // #define USE_REAL_REGISTERCONSOLEVDM
33 #define USE_REACTOS_COLORS
34 // #define USE_DOSBOX_COLORS
36 #if defined(USE_REACTOS_COLORS)
39 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
41 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
42 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
43 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
44 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
45 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
46 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
47 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
48 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
49 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
50 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
51 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
52 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
53 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
54 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
55 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
56 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
57 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
58 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
59 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
60 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
61 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
62 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
63 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
64 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
65 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
66 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
67 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
68 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
69 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
70 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
71 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
72 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
73 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
74 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
75 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
76 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
77 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
78 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
79 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
80 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
81 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
82 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
83 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
84 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
85 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
86 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
87 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
88 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
89 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
90 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
91 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
92 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
93 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
94 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
95 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
96 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
97 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
98 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
99 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
100 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
101 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
102 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
103 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
104 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
107 #elif defined(USE_DOSBOX_COLORS)
110 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
112 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
113 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
114 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
115 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
116 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
117 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
118 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
119 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
120 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
121 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
122 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
123 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
124 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
125 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
126 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
127 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
129 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
130 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
131 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
132 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
133 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
134 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
135 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
136 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
137 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
138 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
139 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
140 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
141 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
142 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
143 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
144 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
146 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
147 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
148 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
149 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
150 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
151 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
152 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
153 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
154 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
155 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
156 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
157 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
158 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
159 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
160 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
161 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
163 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
164 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
165 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
166 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
167 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
168 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
169 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
170 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
171 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
172 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
173 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
174 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
175 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
176 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
177 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
178 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
184 * Default 16-color palette for foreground and background
185 * (corresponding flags in comments).
186 * Taken from subsystems/win32/winsrv/consrv/frontends/gui/conwnd.c
188 static const COLORREF ConsoleColors
[16] =
190 RGB(0, 0, 0), // (Black)
191 RGB(0, 0, 128), // BLUE
192 RGB(0, 128, 0), // GREEN
193 RGB(0, 128, 128), // BLUE | GREEN
194 RGB(128, 0, 0), // RED
195 RGB(128, 0, 128), // BLUE | RED
196 RGB(128, 128, 0), // GREEN | RED
197 RGB(192, 192, 192), // BLUE | GREEN | RED
199 RGB(128, 128, 128), // (Grey) INTENSITY
200 RGB(0, 0, 255), // BLUE | INTENSITY
201 RGB(0, 255, 0), // GREEN | INTENSITY
202 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
203 RGB(255, 0, 0), // RED | INTENSITY
204 RGB(255, 0, 255), // BLUE | RED | INTENSITY
205 RGB(255, 255, 0), // GREEN | RED | INTENSITY
206 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
210 * Console interface -- VGA-mode-agnostic
212 typedef struct _CHAR_CELL
216 } CHAR_CELL
, *PCHAR_CELL
;
217 C_ASSERT(sizeof(CHAR_CELL
) == 2);
219 static LPVOID ConsoleFramebuffer
= NULL
; // Active framebuffer, points to
220 // either TextFramebuffer or a
221 // valid graphics framebuffer.
222 static HPALETTE TextPaletteHandle
= NULL
;
223 static HPALETTE PaletteHandle
= NULL
;
225 static HANDLE StartEvent
= NULL
;
226 static HANDLE EndEvent
= NULL
;
227 static HANDLE AnotherEvent
= NULL
;
229 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo
;
230 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo
;
234 * Text mode -- we always keep a valid text mode framebuffer
235 * even if we are in graphics mode. This is needed in order
236 * to keep a consistent VGA state.
238 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
239 static COORD TextResolution
= {0};
240 static PCHAR_CELL TextFramebuffer
= NULL
;
241 static HANDLE TextConsoleBuffer
= NULL
;
244 static HANDLE GraphicsConsoleBuffer
= NULL
;
245 static HANDLE ConsoleMutex
= NULL
;
246 /* DoubleVision support */
247 static BOOLEAN DoubleWidth
= FALSE
;
248 static BOOLEAN DoubleHeight
= FALSE
;
250 static PHARDWARE_TIMER VSyncTimer
;
251 static PHARDWARE_TIMER HSyncTimer
;
256 static BYTE VgaMemory
[VGA_NUM_BANKS
* VGA_BANK_SIZE
];
258 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
260 static BYTE VgaMiscRegister
;
261 static BYTE VgaFeatureRegister
;
263 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
264 static BYTE VgaSeqRegisters
[VGA_SEQ_MAX_REG
];
266 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
267 static BYTE VgaCrtcRegisters
[VGA_CRTC_MAX_REG
];
269 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
270 static BYTE VgaGcRegisters
[VGA_GC_MAX_REG
];
272 static BOOLEAN VgaAcLatch
= FALSE
;
273 static BOOLEAN VgaAcPalDisable
= TRUE
;
274 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
275 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
277 static BYTE VgaDacMask
= 0xFF;
279 static BOOLEAN VgaDacReadWrite
= FALSE
;
280 static WORD VgaDacIndex
= 0;
281 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
283 // static VGA_REGISTERS VgaRegisters;
285 static ULONGLONG VerticalRetraceCycle
= 0ULL;
286 static ULONGLONG HorizontalRetraceCycle
= 0ULL;
288 static BOOLEAN NeedsUpdate
= FALSE
;
289 static BOOLEAN ModeChanged
= FALSE
;
290 static BOOLEAN CursorChanged
= FALSE
;
291 static BOOLEAN PaletteChanged
= FALSE
;
293 typedef enum _SCREEN_MODE
297 } SCREEN_MODE
, *PSCREEN_MODE
;
299 static SCREEN_MODE ScreenMode
= TEXT_MODE
;
300 static COORD CurrResolution
= {0};
302 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
304 /* RegisterConsoleVDM EMULATION ***********************************************/
306 #include <ntddvdeo.h>
308 #ifdef USE_REAL_REGISTERCONSOLEVDM
310 #define __RegisterConsoleVDM RegisterConsoleVDM
311 #define __InvalidateConsoleDIBits InvalidateConsoleDIBits
316 * This private buffer, per-console, is used by
317 * RegisterConsoleVDM and InvalidateConsoleDIBits.
319 static COORD VDMBufferSize
= {0};
320 static PCHAR_CELL VDMBuffer
= NULL
;
322 static PCHAR_INFO CharBuff
= NULL
; // This is a hack, which is unneeded
323 // for the real RegisterConsoleVDM and
324 // InvalidateConsoleDIBits
328 __RegisterConsoleVDM(IN DWORD dwRegisterFlags
,
329 IN HANDLE hStartHardwareEvent
,
330 IN HANDLE hEndHardwareEvent
,
331 IN HANDLE hErrorHardwareEvent
,
332 IN DWORD dwUnusedVar
,
333 OUT LPDWORD lpVideoStateLength
,
334 OUT PVOID
* lpVideoState
, // PVIDEO_HARDWARE_STATE_HEADER*
335 IN PVOID lpUnusedBuffer
,
336 IN DWORD dwUnusedBufferLength
,
337 IN COORD dwVDMBufferSize
,
338 OUT PVOID
* lpVDMBuffer
)
340 UNREFERENCED_PARAMETER(hErrorHardwareEvent
);
341 UNREFERENCED_PARAMETER(dwUnusedVar
);
342 UNREFERENCED_PARAMETER(lpVideoStateLength
);
343 UNREFERENCED_PARAMETER(lpVideoState
);
344 UNREFERENCED_PARAMETER(lpUnusedBuffer
);
345 UNREFERENCED_PARAMETER(dwUnusedBufferLength
);
348 DPRINT1("__RegisterConsoleVDM(%d)\n", dwRegisterFlags
);
350 if (lpVDMBuffer
== NULL
) return FALSE
;
352 if (dwRegisterFlags
!= 0)
354 // if (hStartHardwareEvent == NULL || hEndHardwareEvent == NULL) return FALSE;
355 if (VDMBuffer
!= NULL
) return FALSE
;
357 VDMBufferSize
= dwVDMBufferSize
;
359 /* HACK: Cache -- to be removed in the real implementation */
360 CharBuff
= RtlAllocateHeap(RtlGetProcessHeap(),
362 VDMBufferSize
.X
* VDMBufferSize
.Y
363 * sizeof(*CharBuff
));
366 VDMBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
368 VDMBufferSize
.X
* VDMBufferSize
.Y
369 * sizeof(*VDMBuffer
));
370 *lpVDMBuffer
= VDMBuffer
;
371 return (VDMBuffer
!= NULL
);
375 /* HACK: Cache -- to be removed in the real implementation */
376 if (CharBuff
) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff
);
379 if (VDMBuffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, VDMBuffer
);
382 VDMBufferSize
.X
= VDMBufferSize
.Y
= 0;
389 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput
,
390 IN PSMALL_RECT lpRect
)
392 if ((hConsoleOutput
== TextConsoleBuffer
) && (VDMBuffer
!= NULL
))
394 /* HACK: Write the cached data to the console */
396 COORD Origin
= { lpRect
->Left
, lpRect
->Top
};
401 for (i
= 0; i
< VDMBufferSize
.Y
; i
++)
403 for (j
= 0; j
< VDMBufferSize
.X
; j
++)
405 CharBuff
[i
* VDMBufferSize
.X
+ j
].Char
.AsciiChar
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Char
;
406 CharBuff
[i
* VDMBufferSize
.X
+ j
].Attributes
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Attributes
;
410 WriteConsoleOutputA(hConsoleOutput
,
417 return InvalidateConsoleDIBits(hConsoleOutput
, lpRect
);
422 /* PRIVATE FUNCTIONS **********************************************************/
424 static inline DWORD
VgaGetAddressSize(VOID
);
425 static VOID
VgaUpdateTextCursor(VOID
);
427 static inline DWORD
VgaGetVideoBaseAddress(VOID
)
429 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
432 static inline DWORD
VgaGetVideoLimitAddress(VOID
)
434 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
437 static VOID
VgaUpdateCursorPosition(VOID
)
440 * Update the cursor position in the VGA registers.
442 WORD Offset
= ConsoleInfo
.dwCursorPosition
.Y
* TextResolution
.X
+
443 ConsoleInfo
.dwCursorPosition
.X
;
445 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
] = LOBYTE(Offset
);
446 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
] = HIBYTE(Offset
);
448 // VidBiosSyncCursorPosition();
449 VgaUpdateTextCursor();
452 static BOOL
VgaAttachToConsoleInternal(PCOORD Resolution
)
456 PVIDEO_HARDWARE_STATE_HEADER State
;
458 #ifdef USE_REAL_REGISTERCONSOLEVDM
459 PCHAR_INFO CharBuff
= NULL
;
462 DWORD AddressSize
, ScanlineSize
;
466 COORD Origin
= { 0, 0 };
468 ASSERT(TextFramebuffer
== NULL
);
470 TextResolution
= *Resolution
;
473 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
474 * in the two following APIs:
475 * SrvRegisterConsoleVDM (corresponding Win32 API: RegisterConsoleVDM)
476 * SrvVDMConsoleOperation (corresponding Win32 API: )
477 * to check whether the current process is a VDM process, and fails otherwise
478 * with the error 0xC0000022 (STATUS_ACCESS_DENIED).
480 * It is worth it to notice that also basesrv.dll does the same only for the
481 * BaseSrvIsFirstVDM API...
485 __RegisterConsoleVDM(1,
488 AnotherEvent
, // NULL,
490 &Length
, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
491 (PVOID
*)&State
, // NULL,
495 (PVOID
*)&TextFramebuffer
);
498 DisplayMessage(L
"RegisterConsoleVDM failed with error %d\n", GetLastError());
503 #ifdef USE_REAL_REGISTERCONSOLEVDM
504 CharBuff
= RtlAllocateHeap(RtlGetProcessHeap(),
506 TextResolution
.X
* TextResolution
.Y
507 * sizeof(*CharBuff
));
515 ConRect
.Top
= ConsoleInfo
.srWindow
.Top
;
516 ConRect
.Right
= ConRect
.Left
+ Resolution
->X
- 1;
517 ConRect
.Bottom
= ConRect
.Top
+ Resolution
->Y
- 1;
519 * Use this trick to effectively resize the console buffer and window,
521 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
522 * is smaller than the current console window size, and:
523 * - SetConsoleWindowInfo fails if the new console window size is larger
524 * than the current console screen buffer size.
526 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
527 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
528 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
529 /* Update the saved console information */
530 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
533 * Copy console data into VGA memory
537 AddressSize
= VgaGetAddressSize();
538 ConRect
.Left
= ConRect
.Top
= 0;
539 ConRect
.Right
= TextResolution
.X
;
540 ConRect
.Bottom
= TextResolution
.Y
;
541 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
543 /* Read the data from the console into the framebuffer... */
544 ReadConsoleOutputA(TextConsoleBuffer
,
550 /* ... and copy the framebuffer into the VGA memory */
552 /* Loop through the scanlines */
553 for (i
= 0; i
< TextResolution
.Y
; i
++)
555 /* Loop through the characters */
556 for (j
= 0; j
< TextResolution
.X
; j
++)
558 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
560 /* Store the character in plane 0 */
561 VgaMemory
[CurrentAddr
] = CharBuff
[i
* TextResolution
.X
+ j
].Char
.AsciiChar
;
563 /* Store the attribute in plane 1 */
564 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuff
[i
* TextResolution
.X
+ j
].Attributes
;
567 /* Move to the next scanline */
568 Address
+= ScanlineSize
;
571 #ifdef USE_REAL_REGISTERCONSOLEVDM
572 if (CharBuff
) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff
);
575 VgaUpdateCursorPosition();
580 static BOOL
IsConsoleHandle(HANDLE hHandle
)
584 /* Check whether the handle may be that of a console... */
585 if ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) != FILE_TYPE_CHAR
)
589 * It may be. Perform another test... The idea comes from the
590 * MSDN description of the WriteConsole API:
592 * "WriteConsole fails if it is used with a standard handle
593 * that is redirected to a file. If an application processes
594 * multilingual output that can be redirected, determine whether
595 * the output handle is a console handle (one method is to call
596 * the GetConsoleMode function and check whether it succeeds).
597 * If the handle is a console handle, call WriteConsole. If the
598 * handle is not a console handle, the output is redirected and
599 * you should call WriteFile to perform the I/O."
601 return GetConsoleMode(hHandle
, &dwMode
);
604 static inline DWORD
VgaGetAddressSize(VOID
)
606 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
608 /* Double-word addressing */
609 return 4; // sizeof(DWORD)
611 else if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
613 /* Byte addressing */
614 return 1; // sizeof(BYTE)
618 /* Word addressing */
619 return 2; // sizeof(WORD)
623 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
625 DWORD Offset
= LOWORD(Address
- VgaGetVideoBaseAddress());
628 /* Check for chain-4 and odd-even mode */
629 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
631 /* The lowest two bits are the plane number */
632 Plane
= Offset
& 0x03;
635 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
637 /* The LSB is the plane number */
638 Plane
= Offset
& 0x01;
643 /* Use the read mode */
644 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
647 /* Return the offset on plane 0 for read mode 1 */
648 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_READ
) return Offset
;
649 else return Offset
+ Plane
* VGA_BANK_SIZE
;
652 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
654 DWORD Offset
= LOWORD(Address
- VgaGetVideoBaseAddress());
656 /* Check for chain-4 and odd-even mode */
657 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
659 /* Clear the lowest two bits since they're used to select the bank */
662 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
664 /* Clear the lowest bit since it's used to select odd/even */
668 /* Return the offset on plane 0 */
672 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
674 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 0x03;
675 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
679 /* In write mode 1 just return the latch register */
680 return VgaLatchRegisters
[Plane
];
685 /* Write modes 0 and 3 rotate the data to the right first */
686 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 0x07;
687 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
691 /* Write mode 2 expands the appropriate bit to all 8 bits */
692 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
698 * In write mode 0, the enable set/reset register decides if the
699 * set/reset bit should be expanded to all 8 bits.
701 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
703 /* Copy the bit from the set/reset register to all 8 bits */
704 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
710 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
711 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 0x03;
713 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
714 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
715 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
719 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
722 /* Then we expand the bit in the set/reset field */
723 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
726 /* Bits cleared in the bitmask are replaced with latch register bits */
727 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
729 /* Return the byte */
733 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
735 /* Check if this is the first time the rectangle is updated */
738 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
739 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
742 /* Expand the rectangle to include the point */
743 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
744 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
745 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
746 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
748 /* Set the update request flag */
752 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
756 /* Copy the colors of the default palette to the DAC and console palette */
757 for (i
= 0; i
< NumOfEntries
; i
++)
759 /* Set the palette entries */
760 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
761 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
762 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
763 Entries
[i
].peFlags
= 0;
765 /* Set the DAC registers */
766 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
767 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
768 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
772 static BOOLEAN
VgaInitializePalette(VOID
)
775 BOOLEAN Result
= FALSE
;
776 LPLOGPALETTE Palette
, TextPalette
;
778 /* Allocate storage space for the palettes */
779 Palette
= RtlAllocateHeap(RtlGetProcessHeap(),
782 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
783 TextPalette
= RtlAllocateHeap(RtlGetProcessHeap(),
786 (VGA_AC_PAL_F_REG
+ 1) * sizeof(PALETTEENTRY
));
787 if ((Palette
== NULL
) || (TextPalette
== NULL
)) goto Cleanup
;
789 /* Initialize the palettes */
790 Palette
->palVersion
= TextPalette
->palVersion
= 0x0300;
791 Palette
->palNumEntries
= VGA_MAX_COLORS
;
792 TextPalette
->palNumEntries
= VGA_AC_PAL_F_REG
+ 1;
794 /* Restore the default graphics palette */
795 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
797 /* Set the default text palette */
798 for (i
= 0; i
< TextPalette
->palNumEntries
; i
++)
800 /* Set the palette entries */
801 TextPalette
->palPalEntry
[i
].peRed
= GetRValue(ConsoleColors
[i
]);
802 TextPalette
->palPalEntry
[i
].peGreen
= GetGValue(ConsoleColors
[i
]);
803 TextPalette
->palPalEntry
[i
].peBlue
= GetBValue(ConsoleColors
[i
]);
804 TextPalette
->palPalEntry
[i
].peFlags
= 0;
807 /* Create the palettes */
808 PaletteHandle
= CreatePalette(Palette
);
809 TextPaletteHandle
= CreatePalette(TextPalette
);
811 if (PaletteHandle
!= NULL
&& TextPaletteHandle
!= NULL
)
813 /* The palettes have been created successfully */
818 /* Free the palettes */
819 if (Palette
) RtlFreeHeap(RtlGetProcessHeap(), 0, Palette
);
820 if (TextPalette
) RtlFreeHeap(RtlGetProcessHeap(), 0, TextPalette
);
824 /* Something failed, delete the palettes */
825 if (PaletteHandle
) DeleteObject(PaletteHandle
);
826 if (TextPaletteHandle
) DeleteObject(TextPaletteHandle
);
832 static VOID
VgaResetPalette(VOID
)
834 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
836 /* Restore the default palette */
837 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
838 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
839 PaletteChanged
= TRUE
;
842 static VOID
VgaSetActiveScreenBuffer(HANDLE ScreenBuffer
)
844 /* Set the active buffer */
845 SetConsoleActiveScreenBuffer(ScreenBuffer
);
847 /* Reinitialize the VDM menu */
849 CreateVdmMenu(ScreenBuffer
);
852 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
855 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
856 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
857 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
858 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
860 LONG Width
= Resolution
->X
;
861 LONG Height
= Resolution
->Y
;
863 /* Use DoubleVision mode if the resolution is too small */
864 DoubleWidth
= (Width
< VGA_MINIMUM_WIDTH
);
865 if (DoubleWidth
) Width
*= 2;
866 DoubleHeight
= (Height
< VGA_MINIMUM_HEIGHT
);
867 if (DoubleHeight
) Height
*= 2;
869 /* Fill the bitmap info header */
870 RtlZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BitmapInfo
->bmiHeader
));
871 BitmapInfo
->bmiHeader
.biSize
= sizeof(BitmapInfo
->bmiHeader
);
872 BitmapInfo
->bmiHeader
.biWidth
= Width
;
873 BitmapInfo
->bmiHeader
.biHeight
= Height
;
874 BitmapInfo
->bmiHeader
.biBitCount
= 8;
875 BitmapInfo
->bmiHeader
.biPlanes
= 1;
876 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
877 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
879 /* Fill the palette data */
880 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
882 /* Fill the console graphics buffer info */
883 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
884 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
885 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
887 /* Create the buffer */
888 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
889 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
891 CONSOLE_GRAPHICS_BUFFER
,
892 &GraphicsBufferInfo
);
893 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
895 /* Save the framebuffer address and mutex */
896 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
897 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
899 /* Clear the framebuffer */
900 RtlZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
902 /* Set the active buffer */
903 VgaSetActiveScreenBuffer(GraphicsConsoleBuffer
);
905 /* Set the graphics mode palette */
906 SetConsolePalette(GraphicsConsoleBuffer
,
910 /* Set the screen mode flag */
911 ScreenMode
= GRAPHICS_MODE
;
916 static VOID
VgaLeaveGraphicsMode(VOID
)
918 /* Release the console framebuffer mutex */
919 ReleaseMutex(ConsoleMutex
);
921 /* Switch back to the default console text buffer */
922 // VgaSetActiveScreenBuffer(TextConsoleBuffer);
924 /* Cleanup the video data */
925 CloseHandle(ConsoleMutex
);
927 ConsoleFramebuffer
= NULL
;
928 CloseHandle(GraphicsConsoleBuffer
);
929 GraphicsConsoleBuffer
= NULL
;
932 DoubleHeight
= FALSE
;
935 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
937 /* Switch to the text buffer */
938 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
940 /* Adjust the text framebuffer if we changed the resolution */
941 if (TextResolution
.X
!= Resolution
->X
||
942 TextResolution
.Y
!= Resolution
->Y
)
944 VgaDetachFromConsole(TRUE
);
947 * VgaAttachToConsoleInternal sets TextResolution to the
948 * new resolution and updates ConsoleInfo.
950 if (!VgaAttachToConsoleInternal(Resolution
))
952 DisplayMessage(L
"An unexpected error occurred!\n");
959 VgaUpdateCursorPosition();
962 /* The active framebuffer is now the text framebuffer */
963 ConsoleFramebuffer
= TextFramebuffer
;
966 * Set the text mode palette.
968 * WARNING: This call should fail on Windows (and therefore
969 * we get the default palette and our external behaviour is
970 * just like Windows' one), but it should success on ReactOS
971 * (so that we get console palette changes even for text-mode
972 * screen-buffers, which is a new feature on ReactOS).
974 SetConsolePalette(TextConsoleBuffer
,
978 /* Set the screen mode flag */
979 ScreenMode
= TEXT_MODE
;
984 static VOID
VgaLeaveTextMode(VOID
)
986 /* Reset the active framebuffer */
987 ConsoleFramebuffer
= NULL
;
990 static VOID
VgaChangeMode(VOID
)
992 COORD NewResolution
= VgaGetDisplayResolution();
993 SCREEN_MODE NewScreenMode
=
994 !(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) ? TEXT_MODE
998 * No need to switch to a different screen mode + resolution
999 * if the new ones are the same as the old ones.
1001 if ((ScreenMode
== NewScreenMode
) &&
1002 (CurrResolution
.X
== NewResolution
.X
&& CurrResolution
.Y
== NewResolution
.Y
))
1007 if (ScreenMode
== GRAPHICS_MODE
)
1009 /* Leave the current graphics mode */
1010 VgaLeaveGraphicsMode();
1014 /* Leave the current text mode */
1018 /* Update the current resolution */
1019 CurrResolution
= NewResolution
;
1021 /* The new screen mode will be updated via the VgaEnterText/GraphicsMode functions */
1023 /* Check if the new mode is alphanumeric */
1024 if (NewScreenMode
== TEXT_MODE
)
1026 /* Enter new text mode */
1027 if (!VgaEnterTextMode(&CurrResolution
))
1029 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
1030 EmulatorTerminate();
1036 /* Enter graphics mode */
1037 if (!VgaEnterGraphicsMode(&CurrResolution
))
1039 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
1040 EmulatorTerminate();
1047 /* Trigger a full update of the screen */
1049 UpdateRectangle
.Left
= 0;
1050 UpdateRectangle
.Top
= 0;
1051 UpdateRectangle
.Right
= CurrResolution
.X
;
1052 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
1054 /* Reset the mode change flag */
1055 ModeChanged
= FALSE
;
1058 static VOID
VgaUpdateFramebuffer(VOID
)
1061 DWORD AddressSize
= VgaGetAddressSize();
1062 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1063 BYTE PresetRowScan
= VgaCrtcRegisters
[VGA_CRTC_PRESET_ROW_SCAN_REG
] & 0x1F;
1064 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
1065 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
])
1066 + PresetRowScan
* ScanlineSize
1067 + ((VgaCrtcRegisters
[VGA_CRTC_PRESET_ROW_SCAN_REG
] >> 5) & 3);
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
;
1084 * Synchronize access to the graphics framebuffer
1085 * with the console framebuffer mutex.
1087 WaitForSingleObject(ConsoleMutex
, INFINITE
);
1089 /* Shift the high bit right by 1 in odd/even mode */
1090 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1092 InterlaceHighBit
>>= 1;
1095 /* Loop through the scanlines */
1096 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1098 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1100 /* Odd-numbered line in interlaced mode - set the high bit */
1101 Address
|= InterlaceHighBit
;
1104 /* Loop through the pixels */
1105 for (j
= 0; j
< CurrResolution
.X
; j
++)
1109 /* Apply horizontal pixel panning */
1110 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1112 X
= j
+ ((VgaAcRegisters
[VGA_AC_HORZ_PANNING_REG
] & 0x0F) >> 1);
1116 X
= j
+ (VgaAcRegisters
[VGA_AC_HORZ_PANNING_REG
] & 0x0F);
1119 /* Check the shifting mode */
1120 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
1122 /* 4 bits shifted from each plane */
1124 /* Check if this is 16 or 256 color mode */
1125 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1127 /* One byte per pixel */
1128 PixelData
= VgaMemory
[(X
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1129 + LOWORD((Address
+ (X
/ VGA_NUM_BANKS
))
1134 /* 4-bits per pixel */
1136 PixelData
= VgaMemory
[(X
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1137 + LOWORD((Address
+ (X
/ (VGA_NUM_BANKS
* 2)))
1140 /* Check if we should use the highest 4 bits or lowest 4 */
1141 if (((X
/ VGA_NUM_BANKS
) % 2) == 0)
1153 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
1155 /* Check if this is 16 or 256 color mode */
1156 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1158 // TODO: NOT IMPLEMENTED
1159 DPRINT1("8-bit interleaved mode is not implemented!\n");
1164 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1165 * then 2 bits shifted from plane 1 and 3 for the next 4
1167 DWORD BankNumber
= (X
/ 4) % 2;
1168 DWORD Offset
= Address
+ (X
/ 8);
1169 BYTE LowPlaneData
= VgaMemory
[BankNumber
* VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
1170 BYTE HighPlaneData
= VgaMemory
[(BankNumber
+ 2) * VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
1172 /* Extract the two bits from each plane */
1173 LowPlaneData
= (LowPlaneData
>> (6 - ((X
% 4) * 2))) & 0x03;
1174 HighPlaneData
= (HighPlaneData
>> (6 - ((X
% 4) * 2))) & 0x03;
1176 /* Combine them into the pixel */
1177 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
1182 /* 1 bit shifted from each plane */
1184 /* Check if this is 16 or 256 color mode */
1185 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1187 /* 8 bits per pixel, 2 on each plane */
1189 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1191 /* The data is on plane k, 4 pixels per byte */
1192 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1193 + LOWORD((Address
+ (X
/ VGA_NUM_BANKS
))
1196 /* The mask of the first bit in the pair */
1197 BYTE BitMask
= 1 << (((3 - (X
% VGA_NUM_BANKS
)) * 2) + 1);
1199 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1200 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
1202 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1203 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
1208 /* 4 bits per pixel, 1 on each plane */
1210 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1212 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1213 + LOWORD((Address
+ (X
/ (VGA_NUM_BANKS
* 2)))
1216 /* If the bit on that plane is set, set it */
1217 if (PlaneData
& (1 << (7 - (X
% 8)))) PixelData
|= 1 << k
;
1222 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
1225 * In 16 color mode, the value is an index to the AC registers
1226 * if external palette access is disabled, otherwise (in case
1227 * of palette loading) it is a blank pixel.
1229 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
1233 /* Take into account DoubleVision mode when checking for pixel updates */
1234 if (DoubleWidth
&& DoubleHeight
)
1236 /* Now check if the resulting pixel data has changed */
1237 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
1239 /* Yes, write the new value */
1240 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1241 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1242 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1243 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1245 /* Mark the specified pixel as changed */
1246 VgaMarkForUpdate(i
, j
);
1249 else if (DoubleWidth
&& !DoubleHeight
)
1251 /* Now check if the resulting pixel data has changed */
1252 if (GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
1254 /* Yes, write the new value */
1255 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1256 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1258 /* Mark the specified pixel as changed */
1259 VgaMarkForUpdate(i
, j
);
1262 else if (!DoubleWidth
&& DoubleHeight
)
1264 /* Now check if the resulting pixel data has changed */
1265 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] != PixelData
)
1267 /* Yes, write the new value */
1268 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] = PixelData
;
1269 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
) + j
] = PixelData
;
1271 /* Mark the specified pixel as changed */
1272 VgaMarkForUpdate(i
, j
);
1275 else // if (!DoubleWidth && !DoubleHeight)
1277 /* Now check if the resulting pixel data has changed */
1278 if (GraphicsBuffer
[i
* CurrResolution
.X
+ j
] != PixelData
)
1280 /* Yes, write the new value */
1281 GraphicsBuffer
[i
* CurrResolution
.X
+ j
] = PixelData
;
1283 /* Mark the specified pixel as changed */
1284 VgaMarkForUpdate(i
, j
);
1289 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1291 /* Clear the high bit */
1292 Address
&= ~InterlaceHighBit
;
1295 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) || (i
& 1))
1297 /* Move to the next scanline */
1298 Address
+= ScanlineSize
;
1303 * Release the console framebuffer mutex
1304 * so that we allow for repainting.
1306 ReleaseMutex(ConsoleMutex
);
1312 PCHAR_CELL CharBuffer
= (PCHAR_CELL
)ConsoleFramebuffer
;
1316 * Technically, the horizontal panning and preset row count should
1317 * affect text mode too. However, it works on pixels and not characters,
1318 * so we can't support it currently.
1321 /* Loop through the scanlines */
1322 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1324 /* Loop through the characters */
1325 for (j
= 0; j
< CurrResolution
.X
; j
++)
1327 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1329 /* Plane 0 holds the character itself */
1330 CharInfo
.Char
= VgaMemory
[CurrentAddr
];
1332 /* Plane 1 holds the attribute */
1333 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
1335 /* Now check if the resulting character data has changed */
1336 if ((CharBuffer
[i
* CurrResolution
.X
+ j
].Char
!= CharInfo
.Char
) ||
1337 (CharBuffer
[i
* CurrResolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
1339 /* Yes, write the new value */
1340 CharBuffer
[i
* CurrResolution
.X
+ j
] = CharInfo
;
1342 /* Mark the specified cell as changed */
1343 VgaMarkForUpdate(i
, j
);
1347 /* Move to the next scanline */
1348 Address
+= ScanlineSize
;
1353 static VOID
VgaUpdateTextCursor(VOID
)
1356 CONSOLE_CURSOR_INFO CursorInfo
;
1358 BOOL CursorVisible
= !(VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x20);
1359 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x1F;
1360 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
1362 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1363 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1364 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
1365 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
1367 /* Just return if we are not in text mode */
1368 if (ScreenMode
!= TEXT_MODE
) return;
1370 if (CursorStart
< CursorEnd
)
1372 /* Visible cursor */
1373 CursorInfo
.bVisible
= CursorVisible
;
1374 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
1379 CursorInfo
.bVisible
= FALSE
;
1380 CursorInfo
.dwSize
= 1; // The size needs to be non-null in order SetConsoleCursorInfo to succeed.
1383 /* Add the cursor skew to the location */
1384 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 0x03;
1386 /* Find the coordinates of the new position */
1387 Position
.X
= (SHORT
)(Location
% ScanlineSize
);
1388 Position
.Y
= (SHORT
)(Location
/ ScanlineSize
);
1390 DPRINT("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position
.X
, Position
.Y
);
1392 /* Update the physical cursor */
1393 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
1394 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
1396 /* Reset the cursor changed flag */
1397 CursorChanged
= FALSE
;
1400 static BYTE WINAPI
VgaReadPort(USHORT Port
)
1402 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1407 return VgaMiscRegister
;
1409 case VGA_INSTAT0_READ
:
1410 return 0; // Not implemented
1412 case VGA_INSTAT1_READ_MONO
:
1413 case VGA_INSTAT1_READ_COLOR
:
1416 BOOLEAN Vsync
, Hsync
;
1417 ULONGLONG Cycles
= GetCycleCount();
1418 ULONG CyclesPerMicrosecond
= (ULONG
)((GetCycleSpeed() + 500000ULL) / 1000000ULL);
1419 ULONG Dots
= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & 1) ? 9 : 8;
1420 ULONG Clock
= ((VgaMiscRegister
>> 2) & 1) ? 28 : 25;
1421 ULONG HorizTotalDots
= ((ULONG
)VgaCrtcRegisters
[VGA_CRTC_HORZ_TOTAL_REG
] + 5) * Dots
;
1422 ULONG VblankStart
, VblankEnd
, HblankStart
, HblankEnd
;
1423 ULONG HblankDuration
, VblankDuration
;
1425 /* Calculate the vertical blanking duration in cycles */
1426 VblankStart
= VgaCrtcRegisters
[VGA_CRTC_START_VERT_BLANKING_REG
] & 0x7F;
1427 VblankEnd
= VgaCrtcRegisters
[VGA_CRTC_END_VERT_BLANKING_REG
] & 0x7F;
1428 if (VblankEnd
< VblankStart
) VblankEnd
|= 0x80;
1429 VblankDuration
= ((VblankEnd
- VblankStart
) * HorizTotalDots
1430 * CyclesPerMicrosecond
+ (Clock
>> 1)) / Clock
;
1432 /* Calculate the horizontal blanking duration in cycles */
1433 HblankStart
= VgaCrtcRegisters
[VGA_CRTC_START_HORZ_BLANKING_REG
] & 0x1F;
1434 HblankEnd
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_BLANKING_REG
] & 0x1F;
1435 if (HblankEnd
< HblankStart
) HblankEnd
|= 0x20;
1436 HblankDuration
= ((HblankEnd
- HblankStart
) * Dots
1437 * CyclesPerMicrosecond
+ (Clock
>> 1)) / Clock
;
1439 Vsync
= (Cycles
- VerticalRetraceCycle
) < (ULONGLONG
)VblankDuration
;
1440 Hsync
= (Cycles
- HorizontalRetraceCycle
) < (ULONGLONG
)HblankDuration
;
1442 /* Reset the AC latch */
1445 /* Reverse the polarity, if needed */
1446 if (VgaMiscRegister
& VGA_MISC_VSYNCP
) Vsync
= !Vsync
;
1447 if (VgaMiscRegister
& VGA_MISC_HSYNCP
) Hsync
= !Hsync
;
1449 /* Set a flag if there is a vertical or horizontal retrace */
1450 if (Vsync
|| Hsync
) Result
|= VGA_STAT_DD
;
1452 /* Set an additional flag if there was a vertical retrace */
1453 if (Vsync
) Result
|= VGA_STAT_VRETRACE
;
1458 case VGA_FEATURE_READ
:
1459 return VgaFeatureRegister
;
1465 return VgaAcRegisters
[VgaAcIndex
];
1471 return VgaSeqRegisters
[VgaSeqIndex
];
1476 case VGA_DAC_READ_INDEX
:
1477 /* This returns the read/write state */
1478 return (VgaDacReadWrite
? 0 : 3);
1480 case VGA_DAC_WRITE_INDEX
:
1481 return (VgaDacIndex
/ 3);
1485 /* Ignore reads in write mode */
1486 if (!VgaDacReadWrite
)
1488 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
1489 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1496 case VGA_CRTC_INDEX_MONO
:
1497 case VGA_CRTC_INDEX_COLOR
:
1498 return VgaCrtcIndex
;
1500 case VGA_CRTC_DATA_MONO
:
1501 case VGA_CRTC_DATA_COLOR
:
1502 return VgaCrtcRegisters
[VgaCrtcIndex
];
1508 return VgaGcRegisters
[VgaGcIndex
];
1511 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1518 static inline VOID
VgaWriteSequencer(BYTE Data
)
1520 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
1522 /* Save the value */
1523 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
1526 static inline VOID
VgaWriteGc(BYTE Data
)
1528 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
1530 /* Save the value */
1531 VgaGcRegisters
[VgaGcIndex
] = Data
;
1533 /* Check the index */
1536 case VGA_GC_MISC_REG
:
1538 /* The GC misc register decides if it's text or graphics mode */
1545 static inline VOID
VgaWriteCrtc(BYTE Data
)
1547 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
1549 /* Save the value */
1550 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
1552 /* Check the index */
1553 switch (VgaCrtcIndex
)
1555 case VGA_CRTC_END_HORZ_DISP_REG
:
1556 case VGA_CRTC_VERT_DISP_END_REG
:
1557 case VGA_CRTC_OVERFLOW_REG
:
1558 case VGA_CRTC_MAX_SCAN_LINE_REG
:
1560 /* The video mode has changed */
1565 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
1566 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
1567 case VGA_CRTC_CURSOR_START_REG
:
1568 case VGA_CRTC_CURSOR_END_REG
:
1570 /* Set the cursor changed flag */
1571 CursorChanged
= TRUE
;
1577 static inline VOID
VgaWriteDac(BYTE Data
)
1579 INT i
, PaletteIndex
;
1583 VgaDacRegisters
[VgaDacIndex
] = Data
;
1585 /* Find the palette index */
1586 PaletteIndex
= VgaDacIndex
/ 3;
1588 /* Fill the entry structure */
1589 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3]);
1590 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 1]);
1591 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 2]);
1594 /* Update the palette entry */
1595 SetPaletteEntries(PaletteHandle
, PaletteIndex
, 1, &Entry
);
1597 /* Check which text palette entries are affected */
1598 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
1600 if (VgaAcRegisters
[i
] == PaletteIndex
)
1602 /* Update the text palette entry */
1603 SetPaletteEntries(TextPaletteHandle
, i
, 1, &Entry
);
1607 /* Set the palette changed flag */
1608 PaletteChanged
= TRUE
;
1610 /* Update the index */
1612 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1615 static inline VOID
VgaWriteAc(BYTE Data
)
1619 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
1621 /* Save the value */
1622 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
1624 if (VgaAcPalDisable
) return;
1626 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
1627 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
1629 /* Update the AC register */
1630 VgaAcRegisters
[VgaAcIndex
] = Data
;
1632 /* Fill the entry structure */
1633 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3]);
1634 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 1]);
1635 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 2]);
1638 /* Update the palette entry and set the palette change flag */
1639 SetPaletteEntries(TextPaletteHandle
, VgaAcIndex
, 1, &Entry
);
1640 PaletteChanged
= TRUE
;
1645 VgaAcRegisters
[VgaAcIndex
] = Data
;
1649 static VOID WINAPI
VgaWritePort(USHORT Port
, BYTE Data
)
1651 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1655 case VGA_MISC_WRITE
:
1657 VgaMiscRegister
= Data
;
1659 if (VgaMiscRegister
& 0x01)
1661 /* Color emulation */
1662 DPRINT1("Color emulation\n");
1664 /* Register the new I/O Ports */
1665 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1666 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1667 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1669 /* Unregister the old ones */
1670 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1671 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1672 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1676 /* Monochrome emulation */
1677 DPRINT1("Monochrome emulation\n");
1679 /* Register the new I/O Ports */
1680 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1681 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1682 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1684 /* Unregister the old ones */
1685 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1686 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1687 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1690 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1694 case VGA_FEATURE_WRITE_MONO
:
1695 case VGA_FEATURE_WRITE_COLOR
:
1697 VgaFeatureRegister
= Data
;
1702 // case VGA_AC_WRITE:
1706 /* Change the index */
1707 BYTE Index
= Data
& 0x1F;
1708 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1711 * Change palette protection by checking for
1712 * the Palette Address Source bit.
1714 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1718 /* Write the data */
1722 /* Toggle the latch */
1723 VgaAcLatch
= !VgaAcLatch
;
1729 /* Set the sequencer index register */
1730 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
1736 /* Call the sequencer function */
1737 VgaWriteSequencer(Data
);
1747 case VGA_DAC_READ_INDEX
:
1749 VgaDacReadWrite
= FALSE
;
1750 VgaDacIndex
= Data
* 3;
1754 case VGA_DAC_WRITE_INDEX
:
1756 VgaDacReadWrite
= TRUE
;
1757 VgaDacIndex
= Data
* 3;
1763 /* Ignore writes in read mode */
1764 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1768 case VGA_CRTC_INDEX_MONO
:
1769 case VGA_CRTC_INDEX_COLOR
:
1771 /* Set the CRTC index register */
1772 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
1776 case VGA_CRTC_DATA_MONO
:
1777 case VGA_CRTC_DATA_COLOR
:
1779 /* Call the CRTC function */
1786 /* Set the GC index register */
1787 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
1793 /* Call the GC function */
1799 DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port
, Data
);
1804 static VOID FASTCALL
VgaVerticalRetrace(ULONGLONG ElapsedTime
)
1806 HANDLE ConsoleBufferHandle
= NULL
;
1808 UNREFERENCED_PARAMETER(ElapsedTime
);
1810 /* Set the vertical retrace cycle */
1811 VerticalRetraceCycle
= GetCycleCount();
1813 /* If nothing has changed, just return */
1814 // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
1817 /* Change the display mode */
1818 if (ModeChanged
) VgaChangeMode();
1820 /* Change the text cursor appearance */
1821 if (CursorChanged
) VgaUpdateTextCursor();
1825 /* Trigger a full update of the screen */
1827 UpdateRectangle
.Left
= 0;
1828 UpdateRectangle
.Top
= 0;
1829 UpdateRectangle
.Right
= CurrResolution
.X
;
1830 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
1832 PaletteChanged
= FALSE
;
1835 /* Update the contents of the framebuffer */
1836 VgaUpdateFramebuffer();
1838 /* Ignore if there's nothing to update */
1839 if (!NeedsUpdate
) return;
1841 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1842 UpdateRectangle
.Left
,
1843 UpdateRectangle
.Top
,
1844 UpdateRectangle
.Right
,
1845 UpdateRectangle
.Bottom
);
1847 /* Check if we are in text or graphics mode */
1848 if (ScreenMode
== GRAPHICS_MODE
)
1851 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
1853 /* In DoubleVision mode, scale the update rectangle */
1856 UpdateRectangle
.Left
*= 2;
1857 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
1861 UpdateRectangle
.Top
*= 2;
1862 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
1868 ConsoleBufferHandle
= TextConsoleBuffer
;
1871 /* Redraw the screen */
1872 __InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
1874 /* Clear the update flag */
1875 NeedsUpdate
= FALSE
;
1878 static VOID FASTCALL
VgaHorizontalRetrace(ULONGLONG ElapsedTime
)
1880 UNREFERENCED_PARAMETER(ElapsedTime
);
1883 HorizontalRetraceCycle
= GetCycleCount();
1886 /* PUBLIC FUNCTIONS ***********************************************************/
1888 COORD
VgaGetDisplayResolution(VOID
)
1891 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1893 /* The low 8 bits are in the display registers */
1894 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
1895 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
1897 /* Set the top bits from the overflow register */
1898 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
1900 Resolution
.Y
|= 1 << 8;
1902 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
1904 Resolution
.Y
|= 1 << 9;
1907 /* Increase the values by 1 */
1911 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1913 /* Multiply the horizontal resolution by the 9/8 dot mode */
1914 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
1917 /* The horizontal resolution is halved in 8-bit mode */
1918 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
1921 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1923 /* Halve the vertical resolution */
1928 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1929 Resolution
.Y
/= MaximumScanLine
;
1932 /* Return the resolution */
1936 BOOLEAN
VgaGetDoubleVisionState(PBOOLEAN Horizontal
, PBOOLEAN Vertical
)
1938 if (GraphicsConsoleBuffer
== NULL
) return FALSE
;
1939 if (Horizontal
) *Horizontal
= DoubleWidth
;
1940 if (Vertical
) *Vertical
= DoubleHeight
;
1944 VOID
VgaRefreshDisplay(VOID
)
1946 VgaVerticalRetrace(0);
1949 VOID NTAPI
VgaReadMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
1953 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
1955 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1957 /* Ignore if video RAM access is disabled */
1958 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1960 if (!(VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_READ
))
1962 /* Loop through each byte */
1963 for (i
= 0; i
< Size
; i
++)
1965 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1967 /* Copy the value to the buffer */
1968 BufPtr
[i
] = VgaMemory
[VideoAddress
];
1973 /* Loop through each byte */
1974 for (i
= 0; i
< Size
; i
++)
1978 /* This should always return a plane 0 address for read mode 1 */
1979 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1981 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1983 /* Don't consider ignored banks */
1984 if (!(VgaGcRegisters
[VGA_GC_COLOR_IGNORE_REG
] & (1 << j
))) continue;
1986 if (VgaGcRegisters
[VGA_GC_COLOR_COMPARE_REG
] & (1 << j
))
1988 /* Comparing with 11111111 */
1989 Result
&= VgaMemory
[j
* VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1993 /* Comparing with 00000000 */
1994 Result
&= ~(VgaMemory
[j
* VGA_BANK_SIZE
+ LOWORD(VideoAddress
)]);
1998 /* Copy the value to the buffer */
2003 /* Load the latch registers */
2004 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
2005 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
2006 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
2007 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
2010 BOOLEAN NTAPI
VgaWriteMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
2014 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
2016 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
2018 /* Ignore if video RAM access is disabled */
2019 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return TRUE
;
2021 /* Also ignore if write access to all planes is disabled */
2022 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return TRUE
;
2024 /* Loop through each byte */
2025 for (i
= 0; i
< Size
; i
++)
2027 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
2029 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
2031 /* Make sure the page is writeable */
2032 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
2034 /* Check if this is chain-4 mode */
2035 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
2037 if (((Address
+ i
) & 0x03) != j
)
2039 /* This plane will not be accessed */
2044 /* Check if this is odd-even mode */
2045 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
2047 if (((Address
+ i
) & 0x01) != (j
& 1))
2049 /* This plane will not be accessed */
2054 /* Copy the value to the VGA memory */
2055 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(BufPtr
[i
], j
);
2062 VOID
VgaClearMemory(VOID
)
2064 RtlZeroMemory(VgaMemory
, sizeof(VgaMemory
));
2067 VOID
VgaWriteFont(UINT FontNumber
, CONST UCHAR
* FontData
, UINT Height
)
2070 PUCHAR FontMemory
= (PUCHAR
)&VgaMemory
[VGA_BANK_SIZE
* VGA_FONT_BANK
+ (FontNumber
* VGA_FONT_SIZE
)];
2072 ASSERT(Height
<= VGA_MAX_FONT_HEIGHT
);
2074 for (i
= 0 ; i
< VGA_FONT_CHARACTERS
; i
++)
2076 /* Write the character */
2077 for (j
= 0; j
< Height
; j
++)
2079 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = FontData
[i
* Height
+ j
];
2082 /* Clear the unused part */
2083 for (j
= Height
; j
< VGA_MAX_FONT_HEIGHT
; j
++)
2085 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = 0;
2090 VOID
ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent
)
2092 DPRINT1("Screen events not handled\n");
2095 BOOL
VgaAttachToConsole(VOID
)
2098 // FIXME: We should go back to the saved screen state
2100 if (TextResolution
.X
== 0 || TextResolution
.Y
== 0)
2101 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
2103 if (TextResolution
.X
== 0) TextResolution
.X
= 80;
2104 if (TextResolution
.Y
== 0) TextResolution
.Y
= 25;
2106 return VgaAttachToConsoleInternal(&TextResolution
);
2109 VOID
VgaDetachFromConsole(BOOL ChangingMode
)
2113 COORD dummySize
= {0};
2116 // FIXME: We should save the screen state
2119 __RegisterConsoleVDM(0,
2131 TextFramebuffer
= NULL
;
2137 /* Restore the old screen buffer */
2138 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2140 /* Restore the original console size */
2143 ConRect
.Right
= ConRect
.Left
+ OrgConsoleBufferInfo
.srWindow
.Right
- OrgConsoleBufferInfo
.srWindow
.Left
;
2144 ConRect
.Bottom
= ConRect
.Top
+ OrgConsoleBufferInfo
.srWindow
.Bottom
- OrgConsoleBufferInfo
.srWindow
.Top
;
2146 * See the following trick explanation in VgaAttachToConsoleInternal.
2148 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
2149 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
2150 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
2152 /* Restore the original cursor shape */
2153 SetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
);
2157 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
2159 /* Save the default text-mode console output handle */
2160 if (!IsConsoleHandle(TextHandle
)) return FALSE
;
2161 TextConsoleBuffer
= TextHandle
;
2163 /* Save the original cursor and console screen buffer information */
2164 if (!GetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
) ||
2165 !GetConsoleScreenBufferInfo(TextConsoleBuffer
, &OrgConsoleBufferInfo
))
2169 ConsoleInfo
= OrgConsoleBufferInfo
;
2171 /* Initialize the VGA palette and fail if it isn't successfully created */
2172 if (!VgaInitializePalette()) return FALSE
;
2173 /***/ VgaResetPalette(); /***/
2175 /* Switch to the text buffer */
2176 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2178 /* Clear the VGA memory */
2181 /* Register the memory hook */
2182 MemInstallFastMemoryHook((PVOID
)0xA0000, 0x20000, VgaReadMemory
, VgaWriteMemory
);
2184 /* Register the I/O Ports */
2185 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
2186 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
2187 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
2188 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
2189 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
2190 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
2191 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
2192 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
2193 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
2194 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
2195 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
2196 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
2197 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
2199 /* CGA ports for compatibility, unimplemented */
2200 RegisterIoPort(0x3D8, VgaReadPort
, VgaWritePort
); // CGA_MODE_CTRL_REG
2201 RegisterIoPort(0x3D9, VgaReadPort
, VgaWritePort
); // CGA_PAL_CTRL_REG
2203 HSyncTimer
= CreateHardwareTimer(HARDWARE_TIMER_ENABLED
, HZ_TO_NS(31469), VgaHorizontalRetrace
);
2204 VSyncTimer
= CreateHardwareTimer(HARDWARE_TIMER_ENABLED
, HZ_TO_NS(60), VgaVerticalRetrace
);
2206 /* Return success */
2210 VOID
VgaCleanup(VOID
)
2212 DestroyHardwareTimer(VSyncTimer
);
2213 DestroyHardwareTimer(HSyncTimer
);
2215 if (ScreenMode
== GRAPHICS_MODE
)
2217 /* Leave the current graphics mode */
2218 VgaLeaveGraphicsMode();
2222 /* Leave the current text mode */
2226 VgaDetachFromConsole(FALSE
);
2227 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
2229 CloseHandle(AnotherEvent
);
2230 CloseHandle(EndEvent
);
2231 CloseHandle(StartEvent
);