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
[] = { 0xAFFFF, 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 BOOLEAN InVerticalRetrace
= FALSE
;
286 static BOOLEAN InHorizontalRetrace
= FALSE
;
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
= 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 Offset
+ Plane
* VGA_BANK_SIZE
;
650 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
652 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
654 /* Check for chain-4 and odd-even mode */
655 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
657 /* Clear the lowest two bits since they're used to select the bank */
660 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
662 /* Clear the lowest bit since it's used to select odd/even */
666 /* Return the offset on plane 0 */
670 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
672 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 0x03;
673 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
677 /* In write mode 1 just return the latch register */
678 return VgaLatchRegisters
[Plane
];
683 /* Write modes 0 and 3 rotate the data to the right first */
684 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 0x07;
685 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
689 /* Write mode 2 expands the appropriate bit to all 8 bits */
690 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
696 * In write mode 0, the enable set/reset register decides if the
697 * set/reset bit should be expanded to all 8 bits.
699 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
701 /* Copy the bit from the set/reset register to all 8 bits */
702 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
708 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
709 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 0x03;
711 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
712 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
713 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
717 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
720 /* Then we expand the bit in the set/reset field */
721 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
724 /* Bits cleared in the bitmask are replaced with latch register bits */
725 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
727 /* Return the byte */
731 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
733 /* Check if this is the first time the rectangle is updated */
736 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
737 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
740 /* Expand the rectangle to include the point */
741 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
742 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
743 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
744 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
746 /* Set the update request flag */
750 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
754 /* Copy the colors of the default palette to the DAC and console palette */
755 for (i
= 0; i
< NumOfEntries
; i
++)
757 /* Set the palette entries */
758 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
759 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
760 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
761 Entries
[i
].peFlags
= 0;
763 /* Set the DAC registers */
764 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
765 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
766 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
770 static BOOLEAN
VgaInitializePalette(VOID
)
773 BOOLEAN Result
= FALSE
;
774 LPLOGPALETTE Palette
, TextPalette
;
776 /* Allocate storage space for the palettes */
777 Palette
= RtlAllocateHeap(RtlGetProcessHeap(),
780 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
781 TextPalette
= RtlAllocateHeap(RtlGetProcessHeap(),
784 (VGA_AC_PAL_F_REG
+ 1) * sizeof(PALETTEENTRY
));
785 if ((Palette
== NULL
) || (TextPalette
== NULL
)) goto Cleanup
;
787 /* Initialize the palettes */
788 Palette
->palVersion
= TextPalette
->palVersion
= 0x0300;
789 Palette
->palNumEntries
= VGA_MAX_COLORS
;
790 TextPalette
->palNumEntries
= VGA_AC_PAL_F_REG
+ 1;
792 /* Restore the default graphics palette */
793 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
795 /* Set the default text palette */
796 for (i
= 0; i
< TextPalette
->palNumEntries
; i
++)
798 /* Set the palette entries */
799 TextPalette
->palPalEntry
[i
].peRed
= GetRValue(ConsoleColors
[i
]);
800 TextPalette
->palPalEntry
[i
].peGreen
= GetGValue(ConsoleColors
[i
]);
801 TextPalette
->palPalEntry
[i
].peBlue
= GetBValue(ConsoleColors
[i
]);
802 TextPalette
->palPalEntry
[i
].peFlags
= 0;
805 /* Create the palettes */
806 PaletteHandle
= CreatePalette(Palette
);
807 TextPaletteHandle
= CreatePalette(TextPalette
);
809 if (PaletteHandle
!= NULL
&& TextPaletteHandle
!= NULL
)
811 /* The palettes have been created successfully */
816 /* Free the palettes */
817 if (Palette
) RtlFreeHeap(RtlGetProcessHeap(), 0, Palette
);
818 if (TextPalette
) RtlFreeHeap(RtlGetProcessHeap(), 0, TextPalette
);
822 /* Something failed, delete the palettes */
823 if (PaletteHandle
) DeleteObject(PaletteHandle
);
824 if (TextPaletteHandle
) DeleteObject(TextPaletteHandle
);
830 static VOID
VgaResetPalette(VOID
)
832 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
834 /* Restore the default palette */
835 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
836 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
837 PaletteChanged
= TRUE
;
840 static VOID
VgaSetActiveScreenBuffer(HANDLE ScreenBuffer
)
842 /* Set the active buffer */
843 SetConsoleActiveScreenBuffer(ScreenBuffer
);
845 /* Reinitialize the VDM menu */
847 CreateVdmMenu(ScreenBuffer
);
850 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
853 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
854 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
855 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
856 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
858 LONG Width
= Resolution
->X
;
859 LONG Height
= Resolution
->Y
;
861 /* Use DoubleVision mode if the resolution is too small */
862 DoubleWidth
= (Width
< VGA_MINIMUM_WIDTH
);
863 if (DoubleWidth
) Width
*= 2;
864 DoubleHeight
= (Height
< VGA_MINIMUM_HEIGHT
);
865 if (DoubleHeight
) Height
*= 2;
867 /* Fill the bitmap info header */
868 RtlZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BitmapInfo
->bmiHeader
));
869 BitmapInfo
->bmiHeader
.biSize
= sizeof(BitmapInfo
->bmiHeader
);
870 BitmapInfo
->bmiHeader
.biWidth
= Width
;
871 BitmapInfo
->bmiHeader
.biHeight
= Height
;
872 BitmapInfo
->bmiHeader
.biBitCount
= 8;
873 BitmapInfo
->bmiHeader
.biPlanes
= 1;
874 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
875 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
877 /* Fill the palette data */
878 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
880 /* Fill the console graphics buffer info */
881 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
882 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
883 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
885 /* Create the buffer */
886 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
887 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
889 CONSOLE_GRAPHICS_BUFFER
,
890 &GraphicsBufferInfo
);
891 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
893 /* Save the framebuffer address and mutex */
894 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
895 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
897 /* Clear the framebuffer */
898 RtlZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
900 /* Set the active buffer */
901 VgaSetActiveScreenBuffer(GraphicsConsoleBuffer
);
903 /* Set the graphics mode palette */
904 SetConsolePalette(GraphicsConsoleBuffer
,
908 /* Set the screen mode flag */
909 ScreenMode
= GRAPHICS_MODE
;
914 static VOID
VgaLeaveGraphicsMode(VOID
)
916 /* Release the console framebuffer mutex */
917 ReleaseMutex(ConsoleMutex
);
919 /* Switch back to the default console text buffer */
920 // VgaSetActiveScreenBuffer(TextConsoleBuffer);
922 /* Cleanup the video data */
923 CloseHandle(ConsoleMutex
);
925 ConsoleFramebuffer
= NULL
;
926 CloseHandle(GraphicsConsoleBuffer
);
927 GraphicsConsoleBuffer
= NULL
;
930 DoubleHeight
= FALSE
;
933 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
935 /* Switch to the text buffer */
936 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
938 /* Adjust the text framebuffer if we changed the resolution */
939 if (TextResolution
.X
!= Resolution
->X
||
940 TextResolution
.Y
!= Resolution
->Y
)
942 VgaDetachFromConsole(TRUE
);
945 * VgaAttachToConsoleInternal sets TextResolution to the
946 * new resolution and updates ConsoleInfo.
948 if (!VgaAttachToConsoleInternal(Resolution
))
950 DisplayMessage(L
"An unexpected error occurred!\n");
957 VgaUpdateCursorPosition();
960 /* The active framebuffer is now the text framebuffer */
961 ConsoleFramebuffer
= TextFramebuffer
;
964 * Set the text mode palette.
966 * WARNING: This call should fail on Windows (and therefore
967 * we get the default palette and our external behaviour is
968 * just like Windows' one), but it should success on ReactOS
969 * (so that we get console palette changes even for text-mode
970 * screen-buffers, which is a new feature on ReactOS).
972 SetConsolePalette(TextConsoleBuffer
,
976 /* Set the screen mode flag */
977 ScreenMode
= TEXT_MODE
;
982 static VOID
VgaLeaveTextMode(VOID
)
984 /* Reset the active framebuffer */
985 ConsoleFramebuffer
= NULL
;
988 static VOID
VgaChangeMode(VOID
)
990 COORD NewResolution
= VgaGetDisplayResolution();
991 SCREEN_MODE NewScreenMode
=
992 !(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) ? TEXT_MODE
996 * No need to switch to a different screen mode + resolution
997 * if the new ones are the same as the old ones.
999 if ((ScreenMode
== NewScreenMode
) &&
1000 (CurrResolution
.X
== NewResolution
.X
&& CurrResolution
.Y
== NewResolution
.Y
))
1005 if (ScreenMode
== GRAPHICS_MODE
)
1007 /* Leave the current graphics mode */
1008 VgaLeaveGraphicsMode();
1012 /* Leave the current text mode */
1016 /* Update the current resolution */
1017 CurrResolution
= NewResolution
;
1019 /* The new screen mode will be updated via the VgaEnterText/GraphicsMode functions */
1021 /* Check if the new mode is alphanumeric */
1022 if (NewScreenMode
== TEXT_MODE
)
1024 /* Enter new text mode */
1025 if (!VgaEnterTextMode(&CurrResolution
))
1027 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
1028 EmulatorTerminate();
1034 /* Enter graphics mode */
1035 if (!VgaEnterGraphicsMode(&CurrResolution
))
1037 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
1038 EmulatorTerminate();
1045 /* Trigger a full update of the screen */
1047 UpdateRectangle
.Left
= 0;
1048 UpdateRectangle
.Top
= 0;
1049 UpdateRectangle
.Right
= CurrResolution
.X
;
1050 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
1052 /* Reset the mode change flag */
1053 ModeChanged
= FALSE
;
1056 static VOID
VgaUpdateFramebuffer(VOID
)
1059 DWORD AddressSize
= VgaGetAddressSize();
1060 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
1061 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
]);
1062 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1065 * If console framebuffer is NULL, that means something went wrong
1066 * earlier and this is the final display refresh.
1068 if (ConsoleFramebuffer
== NULL
) return;
1070 /* Check if we are in text or graphics mode */
1071 if (ScreenMode
== GRAPHICS_MODE
)
1074 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
1075 DWORD InterlaceHighBit
= VGA_INTERLACE_HIGH_BIT
;
1078 * Synchronize access to the graphics framebuffer
1079 * with the console framebuffer mutex.
1081 WaitForSingleObject(ConsoleMutex
, INFINITE
);
1083 /* Shift the high bit right by 1 in odd/even mode */
1084 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1086 InterlaceHighBit
>>= 1;
1089 /* Loop through the scanlines */
1090 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1092 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1094 /* Odd-numbered line in interlaced mode - set the high bit */
1095 Address
|= InterlaceHighBit
;
1098 /* Loop through the pixels */
1099 for (j
= 0; j
< CurrResolution
.X
; j
++)
1103 /* Check the shifting mode */
1104 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
1106 /* 4 bits shifted from each plane */
1108 /* Check if this is 16 or 256 color mode */
1109 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1111 /* One byte per pixel */
1112 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1113 + LOWORD((Address
+ (j
/ VGA_NUM_BANKS
))
1118 /* 4-bits per pixel */
1120 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1121 + LOWORD((Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1124 /* Check if we should use the highest 4 bits or lowest 4 */
1125 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
1137 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
1139 /* Check if this is 16 or 256 color mode */
1140 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1142 // TODO: NOT IMPLEMENTED
1143 DPRINT1("8-bit interleaved mode is not implemented!\n");
1148 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1149 * then 2 bits shifted from plane 1 and 3 for the next 4
1151 DWORD BankNumber
= (j
/ 4) % 2;
1152 DWORD Offset
= Address
+ (j
/ 8);
1153 BYTE LowPlaneData
= VgaMemory
[BankNumber
* VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
1154 BYTE HighPlaneData
= VgaMemory
[(BankNumber
+ 2) * VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
1156 /* Extract the two bits from each plane */
1157 LowPlaneData
= (LowPlaneData
>> (6 - ((j
% 4) * 2))) & 0x03;
1158 HighPlaneData
= (HighPlaneData
>> (6 - ((j
% 4) * 2))) & 0x03;
1160 /* Combine them into the pixel */
1161 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
1166 /* 1 bit shifted from each plane */
1168 /* Check if this is 16 or 256 color mode */
1169 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1171 /* 8 bits per pixel, 2 on each plane */
1173 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1175 /* The data is on plane k, 4 pixels per byte */
1176 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1177 + LOWORD((Address
+ (j
/ VGA_NUM_BANKS
))
1180 /* The mask of the first bit in the pair */
1181 BYTE BitMask
= 1 << (((3 - (j
% VGA_NUM_BANKS
)) * 2) + 1);
1183 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1184 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
1186 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1187 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
1192 /* 4 bits per pixel, 1 on each plane */
1194 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1196 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1197 + LOWORD((Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1200 /* If the bit on that plane is set, set it */
1201 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
1206 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
1209 * In 16 color mode, the value is an index to the AC registers
1210 * if external palette access is disabled, otherwise (in case
1211 * of palette loading) it is a blank pixel.
1213 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
1217 /* Take into account DoubleVision mode when checking for pixel updates */
1218 if (DoubleWidth
&& DoubleHeight
)
1220 /* Now check if the resulting pixel data has changed */
1221 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
1223 /* Yes, write the new value */
1224 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1225 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1226 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1227 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1229 /* Mark the specified pixel as changed */
1230 VgaMarkForUpdate(i
, j
);
1233 else if (DoubleWidth
&& !DoubleHeight
)
1235 /* Now check if the resulting pixel data has changed */
1236 if (GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
1238 /* Yes, write the new value */
1239 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1240 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1242 /* Mark the specified pixel as changed */
1243 VgaMarkForUpdate(i
, j
);
1246 else if (!DoubleWidth
&& DoubleHeight
)
1248 /* Now check if the resulting pixel data has changed */
1249 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] != PixelData
)
1251 /* Yes, write the new value */
1252 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] = PixelData
;
1253 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
) + j
] = PixelData
;
1255 /* Mark the specified pixel as changed */
1256 VgaMarkForUpdate(i
, j
);
1259 else // if (!DoubleWidth && !DoubleHeight)
1261 /* Now check if the resulting pixel data has changed */
1262 if (GraphicsBuffer
[i
* CurrResolution
.X
+ j
] != PixelData
)
1264 /* Yes, write the new value */
1265 GraphicsBuffer
[i
* CurrResolution
.X
+ j
] = PixelData
;
1267 /* Mark the specified pixel as changed */
1268 VgaMarkForUpdate(i
, j
);
1273 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1275 /* Clear the high bit */
1276 Address
&= ~InterlaceHighBit
;
1279 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) || (i
& 1))
1281 /* Move to the next scanline */
1282 Address
+= ScanlineSize
;
1287 * Release the console framebuffer mutex
1288 * so that we allow for repainting.
1290 ReleaseMutex(ConsoleMutex
);
1296 PCHAR_CELL CharBuffer
= (PCHAR_CELL
)ConsoleFramebuffer
;
1299 /* Loop through the scanlines */
1300 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1302 /* Loop through the characters */
1303 for (j
= 0; j
< CurrResolution
.X
; j
++)
1305 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1307 /* Plane 0 holds the character itself */
1308 CharInfo
.Char
= VgaMemory
[CurrentAddr
];
1310 /* Plane 1 holds the attribute */
1311 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
1313 /* Now check if the resulting character data has changed */
1314 if ((CharBuffer
[i
* CurrResolution
.X
+ j
].Char
!= CharInfo
.Char
) ||
1315 (CharBuffer
[i
* CurrResolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
1317 /* Yes, write the new value */
1318 CharBuffer
[i
* CurrResolution
.X
+ j
] = CharInfo
;
1320 /* Mark the specified cell as changed */
1321 VgaMarkForUpdate(i
, j
);
1325 /* Move to the next scanline */
1326 Address
+= ScanlineSize
;
1331 static VOID
VgaUpdateTextCursor(VOID
)
1334 CONSOLE_CURSOR_INFO CursorInfo
;
1336 BOOL CursorVisible
= !(VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x20);
1337 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x1F;
1338 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
1340 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1341 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1342 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
1343 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
1345 /* Just return if we are not in text mode */
1346 if (ScreenMode
!= TEXT_MODE
) return;
1348 if (CursorStart
< CursorEnd
)
1350 /* Visible cursor */
1351 CursorInfo
.bVisible
= CursorVisible
;
1352 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
1357 CursorInfo
.bVisible
= FALSE
;
1358 CursorInfo
.dwSize
= 1; // The size needs to be non-null in order SetConsoleCursorInfo to succeed.
1361 /* Add the cursor skew to the location */
1362 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 0x03;
1364 /* Find the coordinates of the new position */
1365 Position
.X
= (SHORT
)(Location
% ScanlineSize
);
1366 Position
.Y
= (SHORT
)(Location
/ ScanlineSize
);
1368 DPRINT("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position
.X
, Position
.Y
);
1370 /* Update the physical cursor */
1371 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
1372 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
1374 /* Reset the cursor changed flag */
1375 CursorChanged
= FALSE
;
1378 static BYTE WINAPI
VgaReadPort(USHORT Port
)
1380 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1385 return VgaMiscRegister
;
1387 case VGA_INSTAT0_READ
:
1388 return 0; // Not implemented
1390 case VGA_INSTAT1_READ_MONO
:
1391 case VGA_INSTAT1_READ_COLOR
:
1395 /* Reset the AC latch */
1398 /* Set a flag if there is a vertical or horizontal retrace */
1399 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
1401 /* Set an additional flag if there was a vertical retrace */
1402 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
1404 /* Clear the flags */
1405 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
1410 case VGA_FEATURE_READ
:
1411 return VgaFeatureRegister
;
1417 return VgaAcRegisters
[VgaAcIndex
];
1423 return VgaSeqRegisters
[VgaSeqIndex
];
1428 case VGA_DAC_READ_INDEX
:
1429 /* This returns the read/write state */
1430 return (VgaDacReadWrite
? 0 : 3);
1432 case VGA_DAC_WRITE_INDEX
:
1433 return (VgaDacIndex
/ 3);
1437 /* Ignore reads in write mode */
1438 if (!VgaDacReadWrite
)
1440 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
1441 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1448 case VGA_CRTC_INDEX_MONO
:
1449 case VGA_CRTC_INDEX_COLOR
:
1450 return VgaCrtcIndex
;
1452 case VGA_CRTC_DATA_MONO
:
1453 case VGA_CRTC_DATA_COLOR
:
1454 return VgaCrtcRegisters
[VgaCrtcIndex
];
1460 return VgaGcRegisters
[VgaGcIndex
];
1463 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1470 static inline VOID
VgaWriteSequencer(BYTE Data
)
1472 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
1474 /* Save the value */
1475 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
1478 static inline VOID
VgaWriteGc(BYTE Data
)
1480 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
1482 /* Save the value */
1483 VgaGcRegisters
[VgaGcIndex
] = Data
;
1485 /* Check the index */
1488 case VGA_GC_MISC_REG
:
1490 /* The GC misc register decides if it's text or graphics mode */
1497 static inline VOID
VgaWriteCrtc(BYTE Data
)
1499 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
1501 /* Save the value */
1502 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
1504 /* Check the index */
1505 switch (VgaCrtcIndex
)
1507 case VGA_CRTC_END_HORZ_DISP_REG
:
1508 case VGA_CRTC_VERT_DISP_END_REG
:
1509 case VGA_CRTC_OVERFLOW_REG
:
1510 case VGA_CRTC_MAX_SCAN_LINE_REG
:
1512 /* The video mode has changed */
1517 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
1518 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
1519 case VGA_CRTC_CURSOR_START_REG
:
1520 case VGA_CRTC_CURSOR_END_REG
:
1522 /* Set the cursor changed flag */
1523 CursorChanged
= TRUE
;
1529 static inline VOID
VgaWriteDac(BYTE Data
)
1531 INT i
, PaletteIndex
;
1535 VgaDacRegisters
[VgaDacIndex
] = Data
;
1537 /* Find the palette index */
1538 PaletteIndex
= VgaDacIndex
/ 3;
1540 /* Fill the entry structure */
1541 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3]);
1542 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 1]);
1543 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 2]);
1546 /* Update the palette entry */
1547 SetPaletteEntries(PaletteHandle
, PaletteIndex
, 1, &Entry
);
1549 /* Check which text palette entries are affected */
1550 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
1552 if (VgaAcRegisters
[i
] == PaletteIndex
)
1554 /* Update the text palette entry */
1555 SetPaletteEntries(TextPaletteHandle
, i
, 1, &Entry
);
1559 /* Set the palette changed flag */
1560 PaletteChanged
= TRUE
;
1562 /* Update the index */
1564 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1567 static inline VOID
VgaWriteAc(BYTE Data
)
1571 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
1573 /* Save the value */
1574 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
1576 if (VgaAcPalDisable
) return;
1578 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
1579 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
1581 /* Update the AC register */
1582 VgaAcRegisters
[VgaAcIndex
] = Data
;
1584 /* Fill the entry structure */
1585 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3]);
1586 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 1]);
1587 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 2]);
1590 /* Update the palette entry and set the palette change flag */
1591 SetPaletteEntries(TextPaletteHandle
, VgaAcIndex
, 1, &Entry
);
1592 PaletteChanged
= TRUE
;
1597 VgaAcRegisters
[VgaAcIndex
] = Data
;
1601 static VOID WINAPI
VgaWritePort(USHORT Port
, BYTE Data
)
1603 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1607 case VGA_MISC_WRITE
:
1609 VgaMiscRegister
= Data
;
1611 if (VgaMiscRegister
& 0x01)
1613 /* Color emulation */
1614 DPRINT1("Color emulation\n");
1616 /* Register the new I/O Ports */
1617 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1618 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1619 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1621 /* Unregister the old ones */
1622 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1623 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1624 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1628 /* Monochrome emulation */
1629 DPRINT1("Monochrome emulation\n");
1631 /* Register the new I/O Ports */
1632 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1633 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1634 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1636 /* Unregister the old ones */
1637 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1638 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1639 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1642 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1646 case VGA_FEATURE_WRITE_MONO
:
1647 case VGA_FEATURE_WRITE_COLOR
:
1649 VgaFeatureRegister
= Data
;
1654 // case VGA_AC_WRITE:
1658 /* Change the index */
1659 BYTE Index
= Data
& 0x1F;
1660 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1663 * Change palette protection by checking for
1664 * the Palette Address Source bit.
1666 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1670 /* Write the data */
1674 /* Toggle the latch */
1675 VgaAcLatch
= !VgaAcLatch
;
1681 /* Set the sequencer index register */
1682 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
1688 /* Call the sequencer function */
1689 VgaWriteSequencer(Data
);
1699 case VGA_DAC_READ_INDEX
:
1701 VgaDacReadWrite
= FALSE
;
1702 VgaDacIndex
= Data
* 3;
1706 case VGA_DAC_WRITE_INDEX
:
1708 VgaDacReadWrite
= TRUE
;
1709 VgaDacIndex
= Data
* 3;
1715 /* Ignore writes in read mode */
1716 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1720 case VGA_CRTC_INDEX_MONO
:
1721 case VGA_CRTC_INDEX_COLOR
:
1723 /* Set the CRTC index register */
1724 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
1728 case VGA_CRTC_DATA_MONO
:
1729 case VGA_CRTC_DATA_COLOR
:
1731 /* Call the CRTC function */
1738 /* Set the GC index register */
1739 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
1745 /* Call the GC function */
1751 DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port
, Data
);
1756 static VOID FASTCALL
VgaVerticalRetrace(ULONGLONG ElapsedTime
)
1758 HANDLE ConsoleBufferHandle
= NULL
;
1760 UNREFERENCED_PARAMETER(ElapsedTime
);
1762 /* Set the vertical retrace flag */
1763 InVerticalRetrace
= TRUE
;
1765 /* If nothing has changed, just return */
1766 // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
1769 /* Change the display mode */
1770 if (ModeChanged
) VgaChangeMode();
1772 /* Change the text cursor appearance */
1773 if (CursorChanged
) VgaUpdateTextCursor();
1777 /* Trigger a full update of the screen */
1779 UpdateRectangle
.Left
= 0;
1780 UpdateRectangle
.Top
= 0;
1781 UpdateRectangle
.Right
= CurrResolution
.X
;
1782 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
1784 PaletteChanged
= FALSE
;
1787 /* Update the contents of the framebuffer */
1788 VgaUpdateFramebuffer();
1790 /* Ignore if there's nothing to update */
1791 if (!NeedsUpdate
) return;
1793 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1794 UpdateRectangle
.Left
,
1795 UpdateRectangle
.Top
,
1796 UpdateRectangle
.Right
,
1797 UpdateRectangle
.Bottom
);
1799 /* Check if we are in text or graphics mode */
1800 if (ScreenMode
== GRAPHICS_MODE
)
1803 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
1805 /* In DoubleVision mode, scale the update rectangle */
1808 UpdateRectangle
.Left
*= 2;
1809 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
1813 UpdateRectangle
.Top
*= 2;
1814 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
1820 ConsoleBufferHandle
= TextConsoleBuffer
;
1823 /* Redraw the screen */
1824 __InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
1826 /* Clear the update flag */
1827 NeedsUpdate
= FALSE
;
1830 static VOID FASTCALL
VgaHorizontalRetrace(ULONGLONG ElapsedTime
)
1832 UNREFERENCED_PARAMETER(ElapsedTime
);
1835 InHorizontalRetrace
= TRUE
;
1838 /* PUBLIC FUNCTIONS ***********************************************************/
1840 COORD
VgaGetDisplayResolution(VOID
)
1843 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1845 /* The low 8 bits are in the display registers */
1846 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
1847 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
1849 /* Set the top bits from the overflow register */
1850 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
1852 Resolution
.Y
|= 1 << 8;
1854 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
1856 Resolution
.Y
|= 1 << 9;
1859 /* Increase the values by 1 */
1863 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1865 /* Multiply the horizontal resolution by the 9/8 dot mode */
1866 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
1869 /* The horizontal resolution is halved in 8-bit mode */
1870 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
1873 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1875 /* Halve the vertical resolution */
1880 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1881 Resolution
.Y
/= MaximumScanLine
;
1884 /* Return the resolution */
1888 BOOLEAN
VgaGetDoubleVisionState(PBOOLEAN Horizontal
, PBOOLEAN Vertical
)
1890 if (GraphicsConsoleBuffer
== NULL
) return FALSE
;
1891 if (Horizontal
) *Horizontal
= DoubleWidth
;
1892 if (Vertical
) *Vertical
= DoubleHeight
;
1896 VOID
VgaRefreshDisplay(VOID
)
1898 VgaVerticalRetrace(0);
1901 VOID NTAPI
VgaReadMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
1905 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
1907 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1908 Address
= min(max(Address
, VgaGetVideoBaseAddress()), VgaGetVideoLimitAddress());
1909 Size
= min(Size
, VgaGetVideoLimitAddress() - Address
+ 1);
1911 /* Ignore if video RAM access is disabled */
1912 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1914 /* Loop through each byte */
1915 for (i
= 0; i
< Size
; i
++)
1917 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1919 /* Copy the value to the buffer */
1920 BufPtr
[i
] = VgaMemory
[VideoAddress
];
1923 /* Load the latch registers */
1924 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1925 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1926 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1927 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1930 BOOLEAN NTAPI
VgaWriteMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
1934 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
1936 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1937 Address
= min(max(Address
, VgaGetVideoBaseAddress()), VgaGetVideoLimitAddress());
1938 Size
= min(Size
, VgaGetVideoLimitAddress() - Address
+ 1);
1940 /* Ignore if video RAM access is disabled */
1941 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return TRUE
;
1943 /* Also ignore if write access to all planes is disabled */
1944 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return TRUE
;
1946 /* Loop through each byte */
1947 for (i
= 0; i
< Size
; i
++)
1949 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1951 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1953 /* Make sure the page is writeable */
1954 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1956 /* Check if this is chain-4 mode */
1957 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1959 if (((Address
+ i
) & 0x03) != j
)
1961 /* This plane will not be accessed */
1966 /* Check if this is odd-even mode */
1967 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1969 if (((Address
+ i
) & 0x01) != (j
& 1))
1971 /* This plane will not be accessed */
1976 /* Copy the value to the VGA memory */
1977 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(BufPtr
[i
], j
);
1984 VOID
VgaClearMemory(VOID
)
1986 RtlZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1989 VOID
VgaWriteFont(UINT FontNumber
, CONST UCHAR
* FontData
, UINT Height
)
1992 PUCHAR FontMemory
= (PUCHAR
)&VgaMemory
[VGA_BANK_SIZE
* VGA_FONT_BANK
+ (FontNumber
* VGA_FONT_SIZE
)];
1994 ASSERT(Height
<= VGA_MAX_FONT_HEIGHT
);
1996 for (i
= 0 ; i
< VGA_FONT_CHARACTERS
; i
++)
1998 /* Write the character */
1999 for (j
= 0; j
< Height
; j
++)
2001 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = FontData
[i
* Height
+ j
];
2004 /* Clear the unused part */
2005 for (j
= Height
; j
< VGA_MAX_FONT_HEIGHT
; j
++)
2007 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = 0;
2012 VOID
ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent
)
2014 DPRINT1("Screen events not handled\n");
2017 BOOL
VgaAttachToConsole(VOID
)
2020 // FIXME: We should go back to the saved screen state
2022 if (TextResolution
.X
== 0 || TextResolution
.Y
== 0)
2023 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
2025 if (TextResolution
.X
== 0) TextResolution
.X
= 80;
2026 if (TextResolution
.Y
== 0) TextResolution
.Y
= 25;
2028 return VgaAttachToConsoleInternal(&TextResolution
);
2031 VOID
VgaDetachFromConsole(BOOL ChangingMode
)
2035 COORD dummySize
= {0};
2038 // FIXME: We should save the screen state
2041 __RegisterConsoleVDM(0,
2053 TextFramebuffer
= NULL
;
2059 /* Restore the old screen buffer */
2060 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2062 /* Restore the original console size */
2065 ConRect
.Right
= ConRect
.Left
+ OrgConsoleBufferInfo
.srWindow
.Right
- OrgConsoleBufferInfo
.srWindow
.Left
;
2066 ConRect
.Bottom
= ConRect
.Top
+ OrgConsoleBufferInfo
.srWindow
.Bottom
- OrgConsoleBufferInfo
.srWindow
.Top
;
2068 * See the following trick explanation in VgaAttachToConsoleInternal.
2070 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
2071 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
2072 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
2074 /* Restore the original cursor shape */
2075 SetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
);
2079 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
2081 /* Save the default text-mode console output handle */
2082 if (!IsConsoleHandle(TextHandle
)) return FALSE
;
2083 TextConsoleBuffer
= TextHandle
;
2085 /* Save the original cursor and console screen buffer information */
2086 if (!GetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
) ||
2087 !GetConsoleScreenBufferInfo(TextConsoleBuffer
, &OrgConsoleBufferInfo
))
2091 ConsoleInfo
= OrgConsoleBufferInfo
;
2093 /* Initialize the VGA palette and fail if it isn't successfully created */
2094 if (!VgaInitializePalette()) return FALSE
;
2095 /***/ VgaResetPalette(); /***/
2097 /* Switch to the text buffer */
2098 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2100 /* Clear the VGA memory */
2103 /* Register the memory hook */
2104 MemInstallFastMemoryHook((PVOID
)0xA0000, 0x20000, VgaReadMemory
, VgaWriteMemory
);
2106 /* Register the I/O Ports */
2107 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
2108 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
2109 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
2110 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
2111 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
2112 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
2113 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
2114 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
2115 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
2116 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
2117 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
2118 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
2119 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
2121 /* CGA ports for compatibility, unimplemented */
2122 RegisterIoPort(0x3D8, VgaReadPort
, VgaWritePort
); // CGA_MODE_CTRL_REG
2123 RegisterIoPort(0x3D9, VgaReadPort
, VgaWritePort
); // CGA_PAL_CTRL_REG
2125 HSyncTimer
= CreateHardwareTimer(HARDWARE_TIMER_ENABLED
, HZ_TO_NS(31469), VgaHorizontalRetrace
);
2126 VSyncTimer
= CreateHardwareTimer(HARDWARE_TIMER_ENABLED
, HZ_TO_NS(60), VgaVerticalRetrace
);
2128 /* Return success */
2132 VOID
VgaCleanup(VOID
)
2134 DestroyHardwareTimer(VSyncTimer
);
2135 DestroyHardwareTimer(HSyncTimer
);
2137 if (ScreenMode
== GRAPHICS_MODE
)
2139 /* Leave the current graphics mode */
2140 VgaLeaveGraphicsMode();
2144 /* Leave the current text mode */
2148 VgaDetachFromConsole(FALSE
);
2149 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
2151 CloseHandle(AnotherEvent
);
2152 CloseHandle(EndEvent
);
2153 CloseHandle(StartEvent
);