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>
19 /* PRIVATE VARIABLES **********************************************************/
21 static CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
22 static CONST DWORD MemoryLimit
[] = { 0xAFFFF, 0xAFFFF, 0xB7FFF, 0xBFFFF };
25 * Activate this line if you want to use the real
26 * RegisterConsoleVDM API of ReactOS/Windows.
28 // #define USE_REAL_REGISTERCONSOLEVDM
30 #define USE_REACTOS_COLORS
31 // #define USE_DOSBOX_COLORS
33 #if defined(USE_REACTOS_COLORS)
36 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
38 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
39 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
40 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
41 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
42 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
43 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
44 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
45 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
46 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
47 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
48 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
49 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
50 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
51 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
52 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
53 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
54 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
55 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
56 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
57 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
58 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
59 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
60 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
61 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
62 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
63 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
64 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
65 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
66 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
67 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
68 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
69 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
70 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
71 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
72 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
73 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
74 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
75 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
76 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
77 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
78 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
79 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
80 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
81 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
82 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
83 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
84 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
85 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
86 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
87 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
88 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
89 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
90 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
91 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
92 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
93 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
94 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
95 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
96 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
97 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
98 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
99 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
100 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
101 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
104 #elif defined(USE_DOSBOX_COLORS)
107 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
109 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
110 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
111 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
112 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
113 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
114 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
115 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
116 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
117 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
118 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
119 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
120 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
121 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
122 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
123 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
124 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
126 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
127 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
128 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
129 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
130 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
131 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
132 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
133 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
134 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
135 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
136 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
137 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
138 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
139 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
140 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
141 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
143 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
144 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
145 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
146 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
147 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
148 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
149 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
150 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
151 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
152 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
153 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
154 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
155 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
156 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
157 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
158 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
160 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
161 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
162 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
163 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
164 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
165 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
166 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
167 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
168 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
169 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
170 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
171 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
172 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
173 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
174 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
175 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
181 * Default 16-color palette for foreground and background
182 * (corresponding flags in comments).
183 * Taken from subsystems/win32/winsrv/consrv/frontends/gui/conwnd.c
185 static const COLORREF ConsoleColors
[16] =
187 RGB(0, 0, 0), // (Black)
188 RGB(0, 0, 128), // BLUE
189 RGB(0, 128, 0), // GREEN
190 RGB(0, 128, 128), // BLUE | GREEN
191 RGB(128, 0, 0), // RED
192 RGB(128, 0, 128), // BLUE | RED
193 RGB(128, 128, 0), // GREEN | RED
194 RGB(192, 192, 192), // BLUE | GREEN | RED
196 RGB(128, 128, 128), // (Grey) INTENSITY
197 RGB(0, 0, 255), // BLUE | INTENSITY
198 RGB(0, 255, 0), // GREEN | INTENSITY
199 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
200 RGB(255, 0, 0), // RED | INTENSITY
201 RGB(255, 0, 255), // BLUE | RED | INTENSITY
202 RGB(255, 255, 0), // GREEN | RED | INTENSITY
203 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
207 * Console interface -- VGA-mode-agnostic
209 typedef struct _CHAR_CELL
213 } CHAR_CELL
, *PCHAR_CELL
;
214 C_ASSERT(sizeof(CHAR_CELL
) == 2);
216 static LPVOID ConsoleFramebuffer
= NULL
; // Active framebuffer, points to
217 // either TextFramebuffer or a
218 // valid graphics framebuffer.
219 static HPALETTE TextPaletteHandle
= NULL
;
220 static HPALETTE PaletteHandle
= NULL
;
222 static HANDLE StartEvent
= NULL
;
223 static HANDLE EndEvent
= NULL
;
224 static HANDLE AnotherEvent
= NULL
;
226 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo
;
227 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo
;
231 * Text mode -- we always keep a valid text mode framebuffer
232 * even if we are in graphics mode. This is needed in order
233 * to keep a consistent VGA state.
235 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
236 static COORD TextResolution
= {0};
237 static PCHAR_CELL TextFramebuffer
= NULL
;
238 static HANDLE TextConsoleBuffer
= NULL
;
241 static HANDLE GraphicsConsoleBuffer
= NULL
;
242 static HANDLE ConsoleMutex
= NULL
;
243 /* DoubleVision support */
244 static BOOLEAN DoubleWidth
= FALSE
;
245 static BOOLEAN DoubleHeight
= FALSE
;
250 static BYTE VgaMemory
[VGA_NUM_BANKS
* VGA_BANK_SIZE
];
252 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
254 static BYTE VgaMiscRegister
;
255 static BYTE VgaFeatureRegister
;
257 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
258 static BYTE VgaSeqRegisters
[VGA_SEQ_MAX_REG
];
260 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
261 static BYTE VgaCrtcRegisters
[VGA_CRTC_MAX_REG
];
263 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
264 static BYTE VgaGcRegisters
[VGA_GC_MAX_REG
];
266 static BOOLEAN VgaAcLatch
= FALSE
;
267 static BOOLEAN VgaAcPalDisable
= TRUE
;
268 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
269 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
271 static BYTE VgaDacMask
= 0xFF;
273 static BOOLEAN VgaDacReadWrite
= FALSE
;
274 static WORD VgaDacIndex
= 0;
275 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
277 // static VGA_REGISTERS VgaRegisters;
279 static BOOLEAN InVerticalRetrace
= FALSE
;
280 static BOOLEAN InHorizontalRetrace
= FALSE
;
282 static BOOLEAN NeedsUpdate
= FALSE
;
283 static BOOLEAN ModeChanged
= FALSE
;
284 static BOOLEAN CursorChanged
= FALSE
;
285 static BOOLEAN PaletteChanged
= FALSE
;
287 typedef enum _SCREEN_MODE
291 } SCREEN_MODE
, *PSCREEN_MODE
;
293 static SCREEN_MODE ScreenMode
= TEXT_MODE
;
294 static COORD CurrResolution
= {0};
296 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
298 /* RegisterConsoleVDM EMULATION ***********************************************/
300 #include <ntddvdeo.h>
302 #ifdef USE_REAL_REGISTERCONSOLEVDM
304 #define __RegisterConsoleVDM RegisterConsoleVDM
305 #define __InvalidateConsoleDIBits InvalidateConsoleDIBits
310 * This private buffer, per-console, is used by
311 * RegisterConsoleVDM and InvalidateConsoleDIBits.
313 static COORD VDMBufferSize
= {0};
314 static PCHAR_CELL VDMBuffer
= NULL
;
316 static PCHAR_INFO CharBuff
= NULL
; // This is a hack, which is unneeded
317 // for the real RegisterConsoleVDM and
318 // InvalidateConsoleDIBits
322 __RegisterConsoleVDM(IN DWORD dwRegisterFlags
,
323 IN HANDLE hStartHardwareEvent
,
324 IN HANDLE hEndHardwareEvent
,
325 IN HANDLE hErrorHardwareEvent
,
326 IN DWORD dwUnusedVar
,
327 OUT LPDWORD lpVideoStateLength
,
328 OUT PVOID
* lpVideoState
, // PVIDEO_HARDWARE_STATE_HEADER*
329 IN PVOID lpUnusedBuffer
,
330 IN DWORD dwUnusedBufferLength
,
331 IN COORD dwVDMBufferSize
,
332 OUT PVOID
* lpVDMBuffer
)
334 UNREFERENCED_PARAMETER(hErrorHardwareEvent
);
335 UNREFERENCED_PARAMETER(dwUnusedVar
);
336 UNREFERENCED_PARAMETER(lpVideoStateLength
);
337 UNREFERENCED_PARAMETER(lpVideoState
);
338 UNREFERENCED_PARAMETER(lpUnusedBuffer
);
339 UNREFERENCED_PARAMETER(dwUnusedBufferLength
);
342 DPRINT1("__RegisterConsoleVDM(%d)\n", dwRegisterFlags
);
344 if (lpVDMBuffer
== NULL
) return FALSE
;
346 if (dwRegisterFlags
!= 0)
348 // if (hStartHardwareEvent == NULL || hEndHardwareEvent == NULL) return FALSE;
349 if (VDMBuffer
!= NULL
) return FALSE
;
351 VDMBufferSize
= dwVDMBufferSize
;
353 /* HACK: Cache -- to be removed in the real implementation */
354 CharBuff
= HeapAlloc(GetProcessHeap(),
356 VDMBufferSize
.X
* VDMBufferSize
.Y
357 * sizeof(CHAR_INFO
));
360 VDMBuffer
= HeapAlloc(GetProcessHeap(),
362 VDMBufferSize
.X
* VDMBufferSize
.Y
363 * sizeof(CHAR_CELL
));
364 *lpVDMBuffer
= VDMBuffer
;
365 return (VDMBuffer
!= NULL
);
369 /* HACK: Cache -- to be removed in the real implementation */
370 if (CharBuff
) HeapFree(GetProcessHeap(), 0, CharBuff
);
373 if (VDMBuffer
) HeapFree(GetProcessHeap(), 0, VDMBuffer
);
376 VDMBufferSize
.X
= VDMBufferSize
.Y
= 0;
383 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput
,
384 IN PSMALL_RECT lpRect
)
386 if ((hConsoleOutput
== TextConsoleBuffer
) && (VDMBuffer
!= NULL
))
388 /* HACK: Write the cached data to the console */
390 COORD Origin
= { lpRect
->Left
, lpRect
->Top
};
395 for (i
= 0; i
< VDMBufferSize
.Y
; i
++)
397 for (j
= 0; j
< VDMBufferSize
.X
; j
++)
399 CharBuff
[i
* VDMBufferSize
.X
+ j
].Char
.AsciiChar
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Char
;
400 CharBuff
[i
* VDMBufferSize
.X
+ j
].Attributes
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Attributes
;
404 WriteConsoleOutputA(hConsoleOutput
,
411 return InvalidateConsoleDIBits(hConsoleOutput
, lpRect
);
416 /* PRIVATE FUNCTIONS **********************************************************/
418 static inline DWORD
VgaGetAddressSize(VOID
);
419 static VOID
VgaUpdateTextCursor(VOID
);
421 static VOID
VgaUpdateCursorPosition(VOID
)
424 * Update the cursor position in the VGA registers.
426 WORD Offset
= ConsoleInfo
.dwCursorPosition
.Y
* TextResolution
.X
+
427 ConsoleInfo
.dwCursorPosition
.X
;
429 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
] = LOBYTE(Offset
);
430 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
] = HIBYTE(Offset
);
432 // VidBiosSyncCursorPosition();
433 VgaUpdateTextCursor();
436 static BOOL
VgaAttachToConsoleInternal(PCOORD Resolution
)
440 PVIDEO_HARDWARE_STATE_HEADER State
;
442 #ifdef USE_REAL_REGISTERCONSOLEVDM
443 PCHAR_INFO CharBuff
= NULL
;
446 DWORD AddressSize
, ScanlineSize
;
450 COORD Origin
= { 0, 0 };
452 ASSERT(TextFramebuffer
== NULL
);
454 TextResolution
= *Resolution
;
457 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
458 * in the two following APIs:
459 * SrvRegisterConsoleVDM (corresponding Win32 API: RegisterConsoleVDM)
460 * SrvVDMConsoleOperation (corresponding Win32 API: )
461 * to check whether the current process is a VDM process, and fails otherwise
462 * with the error 0xC0000022 (STATUS_ACCESS_DENIED).
464 * It is worth it to notice that also basesrv.dll does the same only for the
465 * BaseSrvIsFirstVDM API...
469 __RegisterConsoleVDM(1,
472 AnotherEvent
, // NULL,
474 &Length
, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
475 (PVOID
*)&State
, // NULL,
479 (PVOID
*)&TextFramebuffer
);
482 DisplayMessage(L
"RegisterConsoleVDM failed with error %d\n", GetLastError());
487 #ifdef USE_REAL_REGISTERCONSOLEVDM
488 CharBuff
= HeapAlloc(GetProcessHeap(),
490 TextResolution
.X
* TextResolution
.Y
491 * sizeof(CHAR_INFO
));
499 ConRect
.Top
= ConsoleInfo
.srWindow
.Top
;
500 ConRect
.Right
= ConRect
.Left
+ Resolution
->X
- 1;
501 ConRect
.Bottom
= ConRect
.Top
+ Resolution
->Y
- 1;
503 * Use this trick to effectively resize the console buffer and window,
505 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
506 * is smaller than the current console window size, and:
507 * - SetConsoleWindowInfo fails if the new console window size is larger
508 * than the current console screen buffer size.
510 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
511 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
512 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
513 /* Update the saved console information */
514 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
517 * Copy console data into VGA memory
521 AddressSize
= VgaGetAddressSize();
522 ConRect
.Left
= ConRect
.Top
= 0;
523 ConRect
.Right
= TextResolution
.X
;
524 ConRect
.Bottom
= TextResolution
.Y
;
525 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
527 /* Read the data from the console into the framebuffer... */
528 ReadConsoleOutputA(TextConsoleBuffer
,
534 /* ... and copy the framebuffer into the VGA memory */
536 /* Loop through the scanlines */
537 for (i
= 0; i
< TextResolution
.Y
; i
++)
539 /* Loop through the characters */
540 for (j
= 0; j
< TextResolution
.X
; j
++)
542 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
544 /* Store the character in plane 0 */
545 VgaMemory
[CurrentAddr
] = CharBuff
[i
* TextResolution
.X
+ j
].Char
.AsciiChar
;
547 /* Store the attribute in plane 1 */
548 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuff
[i
* TextResolution
.X
+ j
].Attributes
;
551 /* Move to the next scanline */
552 Address
+= ScanlineSize
;
555 #ifdef USE_REAL_REGISTERCONSOLEVDM
556 if (CharBuff
) HeapFree(GetProcessHeap(), 0, CharBuff
);
559 VgaUpdateCursorPosition();
564 static BOOL
IsConsoleHandle(HANDLE hHandle
)
568 /* Check whether the handle may be that of a console... */
569 if ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) != FILE_TYPE_CHAR
)
573 * It may be. Perform another test... The idea comes from the
574 * MSDN description of the WriteConsole API:
576 * "WriteConsole fails if it is used with a standard handle
577 * that is redirected to a file. If an application processes
578 * multilingual output that can be redirected, determine whether
579 * the output handle is a console handle (one method is to call
580 * the GetConsoleMode function and check whether it succeeds).
581 * If the handle is a console handle, call WriteConsole. If the
582 * handle is not a console handle, the output is redirected and
583 * you should call WriteFile to perform the I/O."
585 return GetConsoleMode(hHandle
, &dwMode
);
588 static inline DWORD
VgaGetAddressSize(VOID
)
590 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
592 /* Double-word addressing */
593 return 4; // sizeof(DWORD)
595 else if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
597 /* Byte addressing */
598 return 1; // sizeof(BYTE)
602 /* Word addressing */
603 return 2; // sizeof(WORD)
607 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
609 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
612 /* Check for chain-4 and odd-even mode */
613 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
615 /* The lowest two bits are the plane number */
616 Plane
= Offset
& 0x03;
619 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
621 /* The LSB is the plane number */
622 Plane
= Offset
& 0x01;
627 /* Use the read mode */
628 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
631 /* Multiply the offset by the address size */
632 Offset
*= VgaGetAddressSize();
634 return Offset
+ Plane
* VGA_BANK_SIZE
;
637 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
639 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
641 /* Check for chain-4 and odd-even mode */
642 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
644 /* Shift the offset to the right by 2 */
647 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
649 /* Shift the offset to the right by 1 */
653 /* Multiply the offset by the address size */
654 Offset
*= VgaGetAddressSize();
656 /* Return the offset on plane 0 */
660 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
662 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 0x03;
663 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
667 /* In write mode 1 just return the latch register */
668 return VgaLatchRegisters
[Plane
];
673 /* Write modes 0 and 3 rotate the data to the right first */
674 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 0x07;
675 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
679 /* Write mode 2 expands the appropriate bit to all 8 bits */
680 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
686 * In write mode 0, the enable set/reset register decides if the
687 * set/reset bit should be expanded to all 8 bits.
689 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
691 /* Copy the bit from the set/reset register to all 8 bits */
692 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
698 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
699 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 0x03;
701 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
702 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
703 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
707 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
710 /* Then we expand the bit in the set/reset field */
711 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
714 /* Bits cleared in the bitmask are replaced with latch register bits */
715 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
717 /* Return the byte */
721 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
723 /* Check if this is the first time the rectangle is updated */
726 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
727 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
730 /* Expand the rectangle to include the point */
731 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
732 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
733 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
734 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
736 /* Set the update request flag */
740 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
744 /* Copy the colors of the default palette to the DAC and console palette */
745 for (i
= 0; i
< NumOfEntries
; i
++)
747 /* Set the palette entries */
748 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
749 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
750 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
751 Entries
[i
].peFlags
= 0;
753 /* Set the DAC registers */
754 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
755 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
756 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
760 static BOOLEAN
VgaInitializePalette(VOID
)
763 BOOLEAN Result
= FALSE
;
764 LPLOGPALETTE Palette
, TextPalette
;
766 /* Allocate storage space for the palettes */
767 Palette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
770 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
771 TextPalette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
774 (VGA_AC_PAL_F_REG
+ 1) * sizeof(PALETTEENTRY
));
775 if ((Palette
== NULL
) || (TextPalette
== NULL
)) goto Cleanup
;
777 /* Initialize the palettes */
778 Palette
->palVersion
= TextPalette
->palVersion
= 0x0300;
779 Palette
->palNumEntries
= VGA_MAX_COLORS
;
780 TextPalette
->palNumEntries
= VGA_AC_PAL_F_REG
+ 1;
782 /* Restore the default graphics palette */
783 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
785 /* Set the default text palette */
786 for (i
= 0; i
< TextPalette
->palNumEntries
; i
++)
788 /* Set the palette entries */
789 TextPalette
->palPalEntry
[i
].peRed
= GetRValue(ConsoleColors
[i
]);
790 TextPalette
->palPalEntry
[i
].peGreen
= GetGValue(ConsoleColors
[i
]);
791 TextPalette
->palPalEntry
[i
].peBlue
= GetBValue(ConsoleColors
[i
]);
792 TextPalette
->palPalEntry
[i
].peFlags
= 0;
795 /* Create the palettes */
796 PaletteHandle
= CreatePalette(Palette
);
797 TextPaletteHandle
= CreatePalette(TextPalette
);
799 if (PaletteHandle
!= NULL
&& TextPaletteHandle
!= NULL
)
801 /* The palettes have been created successfully */
806 /* Free the palettes */
807 if (Palette
) HeapFree(GetProcessHeap(), 0, Palette
);
808 if (TextPalette
) HeapFree(GetProcessHeap(), 0, TextPalette
);
812 /* Something failed, delete the palettes */
813 if (PaletteHandle
) DeleteObject(PaletteHandle
);
814 if (TextPaletteHandle
) DeleteObject(TextPaletteHandle
);
820 static VOID
VgaResetPalette(VOID
)
822 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
824 /* Restore the default palette */
825 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
826 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
827 PaletteChanged
= TRUE
;
830 static VOID
VgaSetActiveScreenBuffer(HANDLE ScreenBuffer
)
832 /* Set the active buffer */
833 SetConsoleActiveScreenBuffer(ScreenBuffer
);
835 /* Reinitialize the VDM menu */
837 CreateVdmMenu(ScreenBuffer
);
840 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
843 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
844 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
845 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
846 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
848 LONG Width
= Resolution
->X
;
849 LONG Height
= Resolution
->Y
;
851 /* Use DoubleVision mode if the resolution is too small */
852 DoubleWidth
= (Width
< VGA_MINIMUM_WIDTH
);
853 if (DoubleWidth
) Width
*= 2;
854 DoubleHeight
= (Height
< VGA_MINIMUM_HEIGHT
);
855 if (DoubleHeight
) Height
*= 2;
857 /* Fill the bitmap info header */
858 RtlZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BitmapInfo
->bmiHeader
));
859 BitmapInfo
->bmiHeader
.biSize
= sizeof(BitmapInfo
->bmiHeader
);
860 BitmapInfo
->bmiHeader
.biWidth
= Width
;
861 BitmapInfo
->bmiHeader
.biHeight
= Height
;
862 BitmapInfo
->bmiHeader
.biBitCount
= 8;
863 BitmapInfo
->bmiHeader
.biPlanes
= 1;
864 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
865 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
867 /* Fill the palette data */
868 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
870 /* Fill the console graphics buffer info */
871 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
872 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
873 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
875 /* Create the buffer */
876 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
877 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
879 CONSOLE_GRAPHICS_BUFFER
,
880 &GraphicsBufferInfo
);
881 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
883 /* Save the framebuffer address and mutex */
884 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
885 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
887 /* Clear the framebuffer */
888 RtlZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
890 /* Set the active buffer */
891 VgaSetActiveScreenBuffer(GraphicsConsoleBuffer
);
893 /* Set the graphics mode palette */
894 SetConsolePalette(GraphicsConsoleBuffer
,
898 /* Set the screen mode flag */
899 ScreenMode
= GRAPHICS_MODE
;
904 static VOID
VgaLeaveGraphicsMode(VOID
)
906 /* Release the console framebuffer mutex */
907 ReleaseMutex(ConsoleMutex
);
909 /* Switch back to the default console text buffer */
910 // VgaSetActiveScreenBuffer(TextConsoleBuffer);
912 /* Cleanup the video data */
913 CloseHandle(ConsoleMutex
);
915 ConsoleFramebuffer
= NULL
;
916 CloseHandle(GraphicsConsoleBuffer
);
917 GraphicsConsoleBuffer
= NULL
;
920 DoubleHeight
= FALSE
;
923 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
925 /* Switch to the text buffer */
926 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
928 /* Adjust the text framebuffer if we changed the resolution */
929 if (TextResolution
.X
!= Resolution
->X
||
930 TextResolution
.Y
!= Resolution
->Y
)
932 VgaDetachFromConsole(TRUE
);
935 * VgaAttachToConsoleInternal sets TextResolution to the
936 * new resolution and updates ConsoleInfo.
938 if (!VgaAttachToConsoleInternal(Resolution
))
940 DisplayMessage(L
"An unexpected error occurred!\n");
947 VgaUpdateCursorPosition();
950 /* The active framebuffer is now the text framebuffer */
951 ConsoleFramebuffer
= TextFramebuffer
;
954 * Set the text mode palette.
956 * WARNING: This call should fail on Windows (and therefore
957 * we get the default palette and our external behaviour is
958 * just like Windows' one), but it should success on ReactOS
959 * (so that we get console palette changes even for text-mode
960 * screen-buffers, which is a new feature on ReactOS).
962 SetConsolePalette(TextConsoleBuffer
,
966 /* Set the screen mode flag */
967 ScreenMode
= TEXT_MODE
;
972 static VOID
VgaLeaveTextMode(VOID
)
974 /* Reset the active framebuffer */
975 ConsoleFramebuffer
= NULL
;
978 static VOID
VgaChangeMode(VOID
)
980 COORD NewResolution
= VgaGetDisplayResolution();
981 SCREEN_MODE NewScreenMode
=
982 !(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) ? TEXT_MODE
986 * No need to switch to a different screen mode + resolution
987 * if the new ones are the same as the old ones.
989 if ((ScreenMode
== NewScreenMode
) &&
990 (CurrResolution
.X
== NewResolution
.X
&& CurrResolution
.Y
== NewResolution
.Y
))
995 if (ScreenMode
== GRAPHICS_MODE
)
997 /* Leave the current graphics mode */
998 VgaLeaveGraphicsMode();
1002 /* Leave the current text mode */
1006 /* Update the current resolution */
1007 CurrResolution
= NewResolution
;
1009 /* The new screen mode will be updated via the VgaEnterText/GraphicsMode functions */
1011 /* Check if the new mode is alphanumeric */
1012 if (NewScreenMode
== TEXT_MODE
)
1014 /* Enter new text mode */
1015 if (!VgaEnterTextMode(&CurrResolution
))
1017 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
1018 EmulatorTerminate();
1024 /* Enter graphics mode */
1025 if (!VgaEnterGraphicsMode(&CurrResolution
))
1027 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
1028 EmulatorTerminate();
1035 /* Trigger a full update of the screen */
1037 UpdateRectangle
.Left
= 0;
1038 UpdateRectangle
.Top
= 0;
1039 UpdateRectangle
.Right
= CurrResolution
.X
;
1040 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
1042 /* Reset the mode change flag */
1043 ModeChanged
= FALSE
;
1046 static VOID
VgaUpdateFramebuffer(VOID
)
1049 DWORD AddressSize
= VgaGetAddressSize();
1050 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
1051 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
]);
1052 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1055 * If console framebuffer is NULL, that means something went wrong
1056 * earlier and this is the final display refresh.
1058 if (ConsoleFramebuffer
== NULL
) return;
1060 /* Check if we are in text or graphics mode */
1061 if (ScreenMode
== GRAPHICS_MODE
)
1064 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
1065 DWORD InterlaceHighBit
= VGA_INTERLACE_HIGH_BIT
;
1068 * Synchronize access to the graphics framebuffer
1069 * with the console framebuffer mutex.
1071 WaitForSingleObject(ConsoleMutex
, INFINITE
);
1073 /* Shift the high bit right by 1 in odd/even mode */
1074 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1076 InterlaceHighBit
>>= 1;
1079 /* Loop through the scanlines */
1080 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1082 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1084 /* Odd-numbered line in interlaced mode - set the high bit */
1085 Address
|= InterlaceHighBit
;
1088 /* Loop through the pixels */
1089 for (j
= 0; j
< CurrResolution
.X
; j
++)
1093 /* Check the shifting mode */
1094 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
1096 /* 4 bits shifted from each plane */
1098 /* Check if this is 16 or 256 color mode */
1099 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1101 /* One byte per pixel */
1102 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1103 + LOWORD((Address
+ (j
/ VGA_NUM_BANKS
))
1108 /* 4-bits per pixel */
1110 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1111 + LOWORD((Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1114 /* Check if we should use the highest 4 bits or lowest 4 */
1115 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
1127 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
1129 /* Check if this is 16 or 256 color mode */
1130 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1132 // TODO: NOT IMPLEMENTED
1133 DPRINT1("8-bit interleaved mode is not implemented!\n");
1138 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1139 * then 2 bits shifted from plane 1 and 3 for the next 4
1141 DWORD BankNumber
= (j
/ 4) % 2;
1142 DWORD Offset
= Address
+ (j
/ 8);
1143 BYTE LowPlaneData
= VgaMemory
[BankNumber
* VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
1144 BYTE HighPlaneData
= VgaMemory
[(BankNumber
+ 2) * VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
1146 /* Extract the two bits from each plane */
1147 LowPlaneData
= (LowPlaneData
>> (6 - ((j
% 4) * 2))) & 0x03;
1148 HighPlaneData
= (HighPlaneData
>> (6 - ((j
% 4) * 2))) & 0x03;
1150 /* Combine them into the pixel */
1151 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
1156 /* 1 bit shifted from each plane */
1158 /* Check if this is 16 or 256 color mode */
1159 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1161 /* 8 bits per pixel, 2 on each plane */
1163 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1165 /* The data is on plane k, 4 pixels per byte */
1166 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1167 + LOWORD((Address
+ (j
/ VGA_NUM_BANKS
))
1170 /* The mask of the first bit in the pair */
1171 BYTE BitMask
= 1 << (((3 - (j
% VGA_NUM_BANKS
)) * 2) + 1);
1173 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1174 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
1176 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1177 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
1182 /* 4 bits per pixel, 1 on each plane */
1184 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1186 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1187 + LOWORD((Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1190 /* If the bit on that plane is set, set it */
1191 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
1196 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
1199 * In 16 color mode, the value is an index to the AC registers
1200 * if external palette access is disabled, otherwise (in case
1201 * of palette loading) it is a blank pixel.
1203 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
1207 /* Take into account DoubleVision mode when checking for pixel updates */
1208 if (DoubleWidth
&& DoubleHeight
)
1210 /* Now check if the resulting pixel data has changed */
1211 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
1213 /* Yes, write the new value */
1214 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1215 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1216 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1217 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1219 /* Mark the specified pixel as changed */
1220 VgaMarkForUpdate(i
, j
);
1223 else if (DoubleWidth
&& !DoubleHeight
)
1225 /* Now check if the resulting pixel data has changed */
1226 if (GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
1228 /* Yes, write the new value */
1229 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1230 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1232 /* Mark the specified pixel as changed */
1233 VgaMarkForUpdate(i
, j
);
1236 else if (!DoubleWidth
&& DoubleHeight
)
1238 /* Now check if the resulting pixel data has changed */
1239 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] != PixelData
)
1241 /* Yes, write the new value */
1242 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] = PixelData
;
1243 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
) + j
] = 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
+ j
] != PixelData
)
1254 /* Yes, write the new value */
1255 GraphicsBuffer
[i
* CurrResolution
.X
+ j
] = PixelData
;
1257 /* Mark the specified pixel as changed */
1258 VgaMarkForUpdate(i
, j
);
1263 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1265 /* Clear the high bit */
1266 Address
&= ~InterlaceHighBit
;
1269 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) || (i
& 1))
1271 /* Move to the next scanline */
1272 Address
+= ScanlineSize
;
1277 * Release the console framebuffer mutex
1278 * so that we allow for repainting.
1280 ReleaseMutex(ConsoleMutex
);
1286 PCHAR_CELL CharBuffer
= (PCHAR_CELL
)ConsoleFramebuffer
;
1289 /* Loop through the scanlines */
1290 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1292 /* Loop through the characters */
1293 for (j
= 0; j
< CurrResolution
.X
; j
++)
1295 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1297 /* Plane 0 holds the character itself */
1298 CharInfo
.Char
= VgaMemory
[CurrentAddr
];
1300 /* Plane 1 holds the attribute */
1301 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
1303 /* Now check if the resulting character data has changed */
1304 if ((CharBuffer
[i
* CurrResolution
.X
+ j
].Char
!= CharInfo
.Char
) ||
1305 (CharBuffer
[i
* CurrResolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
1307 /* Yes, write the new value */
1308 CharBuffer
[i
* CurrResolution
.X
+ j
] = CharInfo
;
1310 /* Mark the specified cell as changed */
1311 VgaMarkForUpdate(i
, j
);
1315 /* Move to the next scanline */
1316 Address
+= ScanlineSize
;
1321 static VOID
VgaUpdateTextCursor(VOID
)
1324 CONSOLE_CURSOR_INFO CursorInfo
;
1326 BOOL CursorVisible
= !(VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x20);
1327 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x1F;
1328 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
1330 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1331 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1332 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
1333 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
1335 /* Just return if we are not in text mode */
1336 if (ScreenMode
!= TEXT_MODE
) return;
1338 if (CursorStart
< CursorEnd
)
1340 /* Visible cursor */
1341 CursorInfo
.bVisible
= CursorVisible
;
1342 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
1347 CursorInfo
.bVisible
= FALSE
;
1348 CursorInfo
.dwSize
= 1; // The size needs to be non-null in order SetConsoleCursorInfo to succeed.
1351 /* Add the cursor skew to the location */
1352 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 0x03;
1354 /* Find the coordinates of the new position */
1355 Position
.X
= (SHORT
)(Location
% ScanlineSize
);
1356 Position
.Y
= (SHORT
)(Location
/ ScanlineSize
);
1358 DPRINT("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position
.X
, Position
.Y
);
1360 /* Update the physical cursor */
1361 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
1362 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
1364 /* Reset the cursor changed flag */
1365 CursorChanged
= FALSE
;
1368 static BYTE WINAPI
VgaReadPort(USHORT Port
)
1370 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1375 return VgaMiscRegister
;
1377 case VGA_INSTAT0_READ
:
1378 return 0; // Not implemented
1380 case VGA_INSTAT1_READ_MONO
:
1381 case VGA_INSTAT1_READ_COLOR
:
1385 /* Reset the AC latch */
1388 /* Set a flag if there is a vertical or horizontal retrace */
1389 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
1391 /* Set an additional flag if there was a vertical retrace */
1392 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
1394 /* Clear the flags */
1395 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
1400 case VGA_FEATURE_READ
:
1401 return VgaFeatureRegister
;
1407 return VgaAcRegisters
[VgaAcIndex
];
1413 return VgaSeqRegisters
[VgaSeqIndex
];
1418 case VGA_DAC_READ_INDEX
:
1419 /* This returns the read/write state */
1420 return (VgaDacReadWrite
? 0 : 3);
1422 case VGA_DAC_WRITE_INDEX
:
1423 return (VgaDacIndex
/ 3);
1427 /* Ignore reads in write mode */
1428 if (!VgaDacReadWrite
)
1430 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
1431 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1438 case VGA_CRTC_INDEX_MONO
:
1439 case VGA_CRTC_INDEX_COLOR
:
1440 return VgaCrtcIndex
;
1442 case VGA_CRTC_DATA_MONO
:
1443 case VGA_CRTC_DATA_COLOR
:
1444 return VgaCrtcRegisters
[VgaCrtcIndex
];
1450 return VgaGcRegisters
[VgaGcIndex
];
1453 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1460 static inline VOID
VgaWriteSequencer(BYTE Data
)
1462 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
1464 /* Save the value */
1465 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
1468 static inline VOID
VgaWriteGc(BYTE Data
)
1470 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
1472 /* Save the value */
1473 VgaGcRegisters
[VgaGcIndex
] = Data
;
1475 /* Check the index */
1478 case VGA_GC_MISC_REG
:
1480 /* The GC misc register decides if it's text or graphics mode */
1487 static inline VOID
VgaWriteCrtc(BYTE Data
)
1489 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
1491 /* Save the value */
1492 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
1494 /* Check the index */
1495 switch (VgaCrtcIndex
)
1497 case VGA_CRTC_END_HORZ_DISP_REG
:
1498 case VGA_CRTC_VERT_DISP_END_REG
:
1499 case VGA_CRTC_OVERFLOW_REG
:
1500 case VGA_CRTC_MAX_SCAN_LINE_REG
:
1502 /* The video mode has changed */
1507 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
1508 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
1509 case VGA_CRTC_CURSOR_START_REG
:
1510 case VGA_CRTC_CURSOR_END_REG
:
1512 /* Set the cursor changed flag */
1513 CursorChanged
= TRUE
;
1519 static inline VOID
VgaWriteDac(BYTE Data
)
1521 INT i
, PaletteIndex
;
1525 VgaDacRegisters
[VgaDacIndex
] = Data
;
1527 /* Find the palette index */
1528 PaletteIndex
= VgaDacIndex
/ 3;
1530 /* Fill the entry structure */
1531 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3]);
1532 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 1]);
1533 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 2]);
1536 /* Update the palette entry */
1537 SetPaletteEntries(PaletteHandle
, PaletteIndex
, 1, &Entry
);
1539 /* Check which text palette entries are affected */
1540 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
1542 if (VgaAcRegisters
[i
] == PaletteIndex
)
1544 /* Update the text palette entry */
1545 SetPaletteEntries(TextPaletteHandle
, i
, 1, &Entry
);
1549 /* Set the palette changed flag */
1550 PaletteChanged
= TRUE
;
1552 /* Update the index */
1554 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1557 static inline VOID
VgaWriteAc(BYTE Data
)
1561 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
1563 /* Save the value */
1564 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
1566 if (VgaAcPalDisable
) return;
1568 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
1569 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
1571 /* Update the AC register */
1572 VgaAcRegisters
[VgaAcIndex
] = Data
;
1574 /* Fill the entry structure */
1575 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3]);
1576 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 1]);
1577 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 2]);
1580 /* Update the palette entry and set the palette change flag */
1581 SetPaletteEntries(TextPaletteHandle
, VgaAcIndex
, 1, &Entry
);
1582 PaletteChanged
= TRUE
;
1587 VgaAcRegisters
[VgaAcIndex
] = Data
;
1591 static VOID WINAPI
VgaWritePort(USHORT Port
, BYTE Data
)
1593 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1597 case VGA_MISC_WRITE
:
1599 VgaMiscRegister
= Data
;
1601 if (VgaMiscRegister
& 0x01)
1603 /* Color emulation */
1604 DPRINT1("Color emulation\n");
1606 /* Register the new I/O Ports */
1607 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1608 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1609 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1611 /* Unregister the old ones */
1612 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1613 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1614 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1618 /* Monochrome emulation */
1619 DPRINT1("Monochrome emulation\n");
1621 /* Register the new I/O Ports */
1622 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1623 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1624 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1626 /* Unregister the old ones */
1627 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1628 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1629 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1632 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1636 case VGA_FEATURE_WRITE_MONO
:
1637 case VGA_FEATURE_WRITE_COLOR
:
1639 VgaFeatureRegister
= Data
;
1644 // case VGA_AC_WRITE:
1648 /* Change the index */
1649 BYTE Index
= Data
& 0x1F;
1650 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1653 * Change palette protection by checking for
1654 * the Palette Address Source bit.
1656 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1660 /* Write the data */
1664 /* Toggle the latch */
1665 VgaAcLatch
= !VgaAcLatch
;
1671 /* Set the sequencer index register */
1672 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
1678 /* Call the sequencer function */
1679 VgaWriteSequencer(Data
);
1689 case VGA_DAC_READ_INDEX
:
1691 VgaDacReadWrite
= FALSE
;
1692 VgaDacIndex
= Data
* 3;
1696 case VGA_DAC_WRITE_INDEX
:
1698 VgaDacReadWrite
= TRUE
;
1699 VgaDacIndex
= Data
* 3;
1705 /* Ignore writes in read mode */
1706 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1710 case VGA_CRTC_INDEX_MONO
:
1711 case VGA_CRTC_INDEX_COLOR
:
1713 /* Set the CRTC index register */
1714 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
1718 case VGA_CRTC_DATA_MONO
:
1719 case VGA_CRTC_DATA_COLOR
:
1721 /* Call the CRTC function */
1728 /* Set the GC index register */
1729 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
1735 /* Call the GC function */
1741 DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port
, Data
);
1746 /* PUBLIC FUNCTIONS ***********************************************************/
1748 DWORD
VgaGetVideoBaseAddress(VOID
)
1750 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1753 DWORD
VgaGetVideoLimitAddress(VOID
)
1755 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1758 COORD
VgaGetDisplayResolution(VOID
)
1761 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1763 /* The low 8 bits are in the display registers */
1764 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
1765 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
1767 /* Set the top bits from the overflow register */
1768 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
1770 Resolution
.Y
|= 1 << 8;
1772 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
1774 Resolution
.Y
|= 1 << 9;
1777 /* Increase the values by 1 */
1781 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1783 /* Multiply the horizontal resolution by the 9/8 dot mode */
1784 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
1787 /* The horizontal resolution is halved in 8-bit mode */
1788 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
1791 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1793 /* Halve the vertical resolution */
1798 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1799 Resolution
.Y
/= MaximumScanLine
;
1802 /* Return the resolution */
1806 VOID
VgaRefreshDisplay(VOID
)
1808 HANDLE ConsoleBufferHandle
= NULL
;
1810 /* Set the vertical retrace flag */
1811 InVerticalRetrace
= TRUE
;
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 VOID
VgaHorizontalRetrace(VOID
)
1881 InHorizontalRetrace
= TRUE
;
1884 VOID
VgaReadMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1889 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1891 /* Ignore if video RAM access is disabled */
1892 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1894 /* Loop through each byte */
1895 for (i
= 0; i
< Size
; i
++)
1897 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1899 /* Copy the value to the buffer */
1900 Buffer
[i
] = VgaMemory
[VideoAddress
];
1903 /* Load the latch registers */
1904 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1905 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1906 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1907 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1910 VOID
VgaWriteMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1915 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1917 /* Ignore if video RAM access is disabled */
1918 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1920 /* Also ignore if write access to all planes is disabled */
1921 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return;
1923 /* Loop through each byte */
1924 for (i
= 0; i
< Size
; i
++)
1926 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1928 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1930 /* Make sure the page is writeable */
1931 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1933 /* Check if this is chain-4 mode */
1934 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1936 if (((Address
+ i
) & 0x03) != j
)
1938 /* This plane will not be accessed */
1943 /* Check if this is odd-even mode */
1944 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1946 if (((Address
+ i
) & 0x01) != (j
& 1))
1948 /* This plane will not be accessed */
1953 /* Copy the value to the VGA memory */
1954 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(Buffer
[i
], j
);
1959 VOID
VgaClearMemory(VOID
)
1961 RtlZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1964 VOID
VgaWriteFont(UINT FontNumber
, CONST UCHAR
* FontData
, UINT Height
)
1967 PUCHAR FontMemory
= (PUCHAR
)&VgaMemory
[VGA_BANK_SIZE
* VGA_FONT_BANK
+ (FontNumber
* VGA_FONT_SIZE
)];
1969 ASSERT(Height
<= VGA_MAX_FONT_HEIGHT
);
1971 for (i
= 0 ; i
< VGA_FONT_CHARACTERS
; i
++)
1973 /* Write the character */
1974 for (j
= 0; j
< Height
; j
++)
1976 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = FontData
[i
* Height
+ j
];
1979 /* Clear the unused part */
1980 for (j
= Height
; j
< VGA_MAX_FONT_HEIGHT
; j
++)
1982 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = 0;
1987 VOID
ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent
)
1989 DPRINT1("Screen events not handled\n");
1992 BOOL
VgaAttachToConsole(VOID
)
1995 // FIXME: We should go back to the saved screen state
1997 if (TextResolution
.X
== 0 || TextResolution
.Y
== 0)
1998 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
2000 if (TextResolution
.X
== 0) TextResolution
.X
= 80;
2001 if (TextResolution
.Y
== 0) TextResolution
.Y
= 25;
2003 return VgaAttachToConsoleInternal(&TextResolution
);
2006 VOID
VgaDetachFromConsole(BOOL ChangingMode
)
2010 COORD dummySize
= {0};
2013 // FIXME: We should save the screen state
2016 __RegisterConsoleVDM(0,
2028 TextFramebuffer
= NULL
;
2034 /* Restore the old screen buffer */
2035 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2037 /* Restore the original console size */
2040 ConRect
.Right
= ConRect
.Left
+ OrgConsoleBufferInfo
.srWindow
.Right
- OrgConsoleBufferInfo
.srWindow
.Left
;
2041 ConRect
.Bottom
= ConRect
.Top
+ OrgConsoleBufferInfo
.srWindow
.Bottom
- OrgConsoleBufferInfo
.srWindow
.Top
;
2043 * See the following trick explanation in VgaAttachToConsoleInternal.
2045 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
2046 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
2047 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
2049 /* Restore the original cursor shape */
2050 SetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
);
2054 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
2056 /* Save the default text-mode console output handle */
2057 if (!IsConsoleHandle(TextHandle
)) return FALSE
;
2058 TextConsoleBuffer
= TextHandle
;
2060 /* Save the original cursor and console screen buffer information */
2061 if (!GetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
) ||
2062 !GetConsoleScreenBufferInfo(TextConsoleBuffer
, &OrgConsoleBufferInfo
))
2066 ConsoleInfo
= OrgConsoleBufferInfo
;
2068 /* Initialize the VGA palette and fail if it isn't successfully created */
2069 if (!VgaInitializePalette()) return FALSE
;
2070 /***/ VgaResetPalette(); /***/
2072 /* Switch to the text buffer */
2073 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2075 /* Clear the VGA memory */
2078 /* Register the I/O Ports */
2079 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
2080 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
2081 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
2082 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
2083 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
2084 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
2085 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
2086 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
2087 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
2088 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
2089 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
2090 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
2091 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
2093 /* CGA ports for compatibility, unimplemented */
2094 RegisterIoPort(0x3D8, VgaReadPort
, VgaWritePort
); // CGA_MODE_CTRL_REG
2095 RegisterIoPort(0x3D9, VgaReadPort
, VgaWritePort
); // CGA_PAL_CTRL_REG
2097 /* Return success */
2101 VOID
VgaCleanup(VOID
)
2103 if (ScreenMode
== GRAPHICS_MODE
)
2105 /* Leave the current graphics mode */
2106 VgaLeaveGraphicsMode();
2110 /* Leave the current text mode */
2114 VgaDetachFromConsole(FALSE
);
2116 CloseHandle(AnotherEvent
);
2117 CloseHandle(EndEvent
);
2118 CloseHandle(StartEvent
);