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>
20 /* PRIVATE VARIABLES **********************************************************/
22 static CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
23 static CONST DWORD MemoryLimit
[] = { 0xAFFFF, 0xAFFFF, 0xB7FFF, 0xBFFFF };
26 * Activate this line if you want to use the real
27 * RegisterConsoleVDM API of ReactOS/Windows.
29 // #define USE_REAL_REGISTERCONSOLEVDM
31 #define USE_REACTOS_COLORS
32 // #define USE_DOSBOX_COLORS
34 #if defined(USE_REACTOS_COLORS)
37 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
39 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
40 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
41 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
42 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
43 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
44 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
45 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
46 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
47 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
48 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
49 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
50 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
51 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
52 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
53 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
54 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
55 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
56 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
57 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
58 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
59 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
60 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
61 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
62 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
63 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
64 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
65 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
66 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
67 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
68 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
69 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
70 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
71 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
72 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
73 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
74 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
75 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
76 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
77 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
78 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
79 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
80 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
81 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
82 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
83 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
84 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
85 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
86 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
87 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
88 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
89 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
90 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
91 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
92 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
93 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
94 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
95 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
96 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
97 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
98 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
99 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
100 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
101 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
102 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
105 #elif defined(USE_DOSBOX_COLORS)
108 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
110 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
111 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
112 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
113 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
114 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
115 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
116 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
117 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
118 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
119 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
120 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
121 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
122 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
123 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
124 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
125 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
127 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
128 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
129 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
130 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
131 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
132 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
133 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
134 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
135 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
136 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
137 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
138 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
139 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
140 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
141 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
142 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
144 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
145 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
146 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
147 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
148 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
149 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
150 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
151 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
152 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
153 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
154 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
155 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
156 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
157 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
158 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
159 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
161 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
162 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
163 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
164 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
165 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
166 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
167 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
168 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
169 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
170 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
171 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
172 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
173 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
174 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
175 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
176 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
182 * Default 16-color palette for foreground and background
183 * (corresponding flags in comments).
184 * Taken from subsystems/win32/winsrv/consrv/frontends/gui/conwnd.c
186 static const COLORREF ConsoleColors
[16] =
188 RGB(0, 0, 0), // (Black)
189 RGB(0, 0, 128), // BLUE
190 RGB(0, 128, 0), // GREEN
191 RGB(0, 128, 128), // BLUE | GREEN
192 RGB(128, 0, 0), // RED
193 RGB(128, 0, 128), // BLUE | RED
194 RGB(128, 128, 0), // GREEN | RED
195 RGB(192, 192, 192), // BLUE | GREEN | RED
197 RGB(128, 128, 128), // (Grey) INTENSITY
198 RGB(0, 0, 255), // BLUE | INTENSITY
199 RGB(0, 255, 0), // GREEN | INTENSITY
200 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
201 RGB(255, 0, 0), // RED | INTENSITY
202 RGB(255, 0, 255), // BLUE | RED | INTENSITY
203 RGB(255, 255, 0), // GREEN | RED | INTENSITY
204 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
208 * Console interface -- VGA-mode-agnostic
210 typedef struct _CHAR_CELL
214 } CHAR_CELL
, *PCHAR_CELL
;
215 C_ASSERT(sizeof(CHAR_CELL
) == 2);
217 static LPVOID ConsoleFramebuffer
= NULL
; // Active framebuffer, points to
218 // either TextFramebuffer or a
219 // valid graphics framebuffer.
220 static HPALETTE TextPaletteHandle
= NULL
;
221 static HPALETTE PaletteHandle
= NULL
;
223 static HANDLE StartEvent
= NULL
;
224 static HANDLE EndEvent
= NULL
;
225 static HANDLE AnotherEvent
= NULL
;
227 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo
;
228 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo
;
232 * Text mode -- we always keep a valid text mode framebuffer
233 * even if we are in graphics mode. This is needed in order
234 * to keep a consistent VGA state.
236 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
237 static COORD TextResolution
= {0};
238 static PCHAR_CELL TextFramebuffer
= NULL
;
239 static HANDLE TextConsoleBuffer
= NULL
;
242 static HANDLE GraphicsConsoleBuffer
= NULL
;
243 static HANDLE ConsoleMutex
= NULL
;
244 /* DoubleVision support */
245 static BOOLEAN DoubleWidth
= FALSE
;
246 static BOOLEAN DoubleHeight
= FALSE
;
251 static BYTE VgaMemory
[VGA_NUM_BANKS
* VGA_BANK_SIZE
];
253 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
255 static BYTE VgaMiscRegister
;
256 static BYTE VgaFeatureRegister
;
258 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
259 static BYTE VgaSeqRegisters
[VGA_SEQ_MAX_REG
];
261 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
262 static BYTE VgaCrtcRegisters
[VGA_CRTC_MAX_REG
];
264 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
265 static BYTE VgaGcRegisters
[VGA_GC_MAX_REG
];
267 static BOOLEAN VgaAcLatch
= FALSE
;
268 static BOOLEAN VgaAcPalDisable
= TRUE
;
269 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
270 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
272 static BYTE VgaDacMask
= 0xFF;
274 static BOOLEAN VgaDacReadWrite
= FALSE
;
275 static WORD VgaDacIndex
= 0;
276 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
278 // static VGA_REGISTERS VgaRegisters;
280 static BOOLEAN InVerticalRetrace
= FALSE
;
281 static BOOLEAN InHorizontalRetrace
= FALSE
;
283 static BOOLEAN NeedsUpdate
= FALSE
;
284 static BOOLEAN ModeChanged
= FALSE
;
285 static BOOLEAN CursorChanged
= FALSE
;
286 static BOOLEAN PaletteChanged
= FALSE
;
288 typedef enum _SCREEN_MODE
292 } SCREEN_MODE
, *PSCREEN_MODE
;
294 static SCREEN_MODE ScreenMode
= TEXT_MODE
;
295 static COORD CurrResolution
= {0};
297 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
299 /* RegisterConsoleVDM EMULATION ***********************************************/
301 #include <ntddvdeo.h>
303 #ifdef USE_REAL_REGISTERCONSOLEVDM
305 #define __RegisterConsoleVDM RegisterConsoleVDM
306 #define __InvalidateConsoleDIBits InvalidateConsoleDIBits
311 * This private buffer, per-console, is used by
312 * RegisterConsoleVDM and InvalidateConsoleDIBits.
314 static COORD VDMBufferSize
= {0};
315 static PCHAR_CELL VDMBuffer
= NULL
;
317 static PCHAR_INFO CharBuff
= NULL
; // This is a hack, which is unneeded
318 // for the real RegisterConsoleVDM and
319 // InvalidateConsoleDIBits
323 __RegisterConsoleVDM(IN DWORD dwRegisterFlags
,
324 IN HANDLE hStartHardwareEvent
,
325 IN HANDLE hEndHardwareEvent
,
326 IN HANDLE hErrorHardwareEvent
,
327 IN DWORD dwUnusedVar
,
328 OUT LPDWORD lpVideoStateLength
,
329 OUT PVOID
* lpVideoState
, // PVIDEO_HARDWARE_STATE_HEADER*
330 IN PVOID lpUnusedBuffer
,
331 IN DWORD dwUnusedBufferLength
,
332 IN COORD dwVDMBufferSize
,
333 OUT PVOID
* lpVDMBuffer
)
335 UNREFERENCED_PARAMETER(hErrorHardwareEvent
);
336 UNREFERENCED_PARAMETER(dwUnusedVar
);
337 UNREFERENCED_PARAMETER(lpVideoStateLength
);
338 UNREFERENCED_PARAMETER(lpVideoState
);
339 UNREFERENCED_PARAMETER(lpUnusedBuffer
);
340 UNREFERENCED_PARAMETER(dwUnusedBufferLength
);
343 DPRINT1("__RegisterConsoleVDM(%d)\n", dwRegisterFlags
);
345 if (lpVDMBuffer
== NULL
) return FALSE
;
347 if (dwRegisterFlags
!= 0)
349 // if (hStartHardwareEvent == NULL || hEndHardwareEvent == NULL) return FALSE;
350 if (VDMBuffer
!= NULL
) return FALSE
;
352 VDMBufferSize
= dwVDMBufferSize
;
354 /* HACK: Cache -- to be removed in the real implementation */
355 CharBuff
= HeapAlloc(GetProcessHeap(),
357 VDMBufferSize
.X
* VDMBufferSize
.Y
358 * sizeof(CHAR_INFO
));
361 VDMBuffer
= HeapAlloc(GetProcessHeap(),
363 VDMBufferSize
.X
* VDMBufferSize
.Y
364 * sizeof(CHAR_CELL
));
365 *lpVDMBuffer
= VDMBuffer
;
366 return (VDMBuffer
!= NULL
);
370 /* HACK: Cache -- to be removed in the real implementation */
371 if (CharBuff
) HeapFree(GetProcessHeap(), 0, CharBuff
);
374 if (VDMBuffer
) HeapFree(GetProcessHeap(), 0, VDMBuffer
);
377 VDMBufferSize
.X
= VDMBufferSize
.Y
= 0;
384 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput
,
385 IN PSMALL_RECT lpRect
)
387 if ((hConsoleOutput
== TextConsoleBuffer
) && (VDMBuffer
!= NULL
))
389 /* HACK: Write the cached data to the console */
391 COORD Origin
= { lpRect
->Left
, lpRect
->Top
};
396 for (i
= 0; i
< VDMBufferSize
.Y
; i
++)
398 for (j
= 0; j
< VDMBufferSize
.X
; j
++)
400 CharBuff
[i
* VDMBufferSize
.X
+ j
].Char
.AsciiChar
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Char
;
401 CharBuff
[i
* VDMBufferSize
.X
+ j
].Attributes
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Attributes
;
405 WriteConsoleOutputA(hConsoleOutput
,
412 return InvalidateConsoleDIBits(hConsoleOutput
, lpRect
);
417 /* PRIVATE FUNCTIONS **********************************************************/
419 static inline DWORD
VgaGetAddressSize(VOID
);
420 static VOID
VgaUpdateTextCursor(VOID
);
422 static inline DWORD
VgaGetVideoBaseAddress(VOID
)
424 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
427 static inline DWORD
VgaGetVideoLimitAddress(VOID
)
429 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
432 static VOID
VgaUpdateCursorPosition(VOID
)
435 * Update the cursor position in the VGA registers.
437 WORD Offset
= ConsoleInfo
.dwCursorPosition
.Y
* TextResolution
.X
+
438 ConsoleInfo
.dwCursorPosition
.X
;
440 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
] = LOBYTE(Offset
);
441 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
] = HIBYTE(Offset
);
443 // VidBiosSyncCursorPosition();
444 VgaUpdateTextCursor();
447 static BOOL
VgaAttachToConsoleInternal(PCOORD Resolution
)
451 PVIDEO_HARDWARE_STATE_HEADER State
;
453 #ifdef USE_REAL_REGISTERCONSOLEVDM
454 PCHAR_INFO CharBuff
= NULL
;
457 DWORD AddressSize
, ScanlineSize
;
461 COORD Origin
= { 0, 0 };
463 ASSERT(TextFramebuffer
== NULL
);
465 TextResolution
= *Resolution
;
468 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
469 * in the two following APIs:
470 * SrvRegisterConsoleVDM (corresponding Win32 API: RegisterConsoleVDM)
471 * SrvVDMConsoleOperation (corresponding Win32 API: )
472 * to check whether the current process is a VDM process, and fails otherwise
473 * with the error 0xC0000022 (STATUS_ACCESS_DENIED).
475 * It is worth it to notice that also basesrv.dll does the same only for the
476 * BaseSrvIsFirstVDM API...
480 __RegisterConsoleVDM(1,
483 AnotherEvent
, // NULL,
485 &Length
, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
486 (PVOID
*)&State
, // NULL,
490 (PVOID
*)&TextFramebuffer
);
493 DisplayMessage(L
"RegisterConsoleVDM failed with error %d\n", GetLastError());
498 #ifdef USE_REAL_REGISTERCONSOLEVDM
499 CharBuff
= HeapAlloc(GetProcessHeap(),
501 TextResolution
.X
* TextResolution
.Y
502 * sizeof(CHAR_INFO
));
510 ConRect
.Top
= ConsoleInfo
.srWindow
.Top
;
511 ConRect
.Right
= ConRect
.Left
+ Resolution
->X
- 1;
512 ConRect
.Bottom
= ConRect
.Top
+ Resolution
->Y
- 1;
514 * Use this trick to effectively resize the console buffer and window,
516 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
517 * is smaller than the current console window size, and:
518 * - SetConsoleWindowInfo fails if the new console window size is larger
519 * than the current console screen buffer size.
521 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
522 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
523 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
524 /* Update the saved console information */
525 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
528 * Copy console data into VGA memory
532 AddressSize
= VgaGetAddressSize();
533 ConRect
.Left
= ConRect
.Top
= 0;
534 ConRect
.Right
= TextResolution
.X
;
535 ConRect
.Bottom
= TextResolution
.Y
;
536 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
538 /* Read the data from the console into the framebuffer... */
539 ReadConsoleOutputA(TextConsoleBuffer
,
545 /* ... and copy the framebuffer into the VGA memory */
547 /* Loop through the scanlines */
548 for (i
= 0; i
< TextResolution
.Y
; i
++)
550 /* Loop through the characters */
551 for (j
= 0; j
< TextResolution
.X
; j
++)
553 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
555 /* Store the character in plane 0 */
556 VgaMemory
[CurrentAddr
] = CharBuff
[i
* TextResolution
.X
+ j
].Char
.AsciiChar
;
558 /* Store the attribute in plane 1 */
559 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuff
[i
* TextResolution
.X
+ j
].Attributes
;
562 /* Move to the next scanline */
563 Address
+= ScanlineSize
;
566 #ifdef USE_REAL_REGISTERCONSOLEVDM
567 if (CharBuff
) HeapFree(GetProcessHeap(), 0, CharBuff
);
570 VgaUpdateCursorPosition();
575 static BOOL
IsConsoleHandle(HANDLE hHandle
)
579 /* Check whether the handle may be that of a console... */
580 if ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) != FILE_TYPE_CHAR
)
584 * It may be. Perform another test... The idea comes from the
585 * MSDN description of the WriteConsole API:
587 * "WriteConsole fails if it is used with a standard handle
588 * that is redirected to a file. If an application processes
589 * multilingual output that can be redirected, determine whether
590 * the output handle is a console handle (one method is to call
591 * the GetConsoleMode function and check whether it succeeds).
592 * If the handle is a console handle, call WriteConsole. If the
593 * handle is not a console handle, the output is redirected and
594 * you should call WriteFile to perform the I/O."
596 return GetConsoleMode(hHandle
, &dwMode
);
599 static inline DWORD
VgaGetAddressSize(VOID
)
601 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
603 /* Double-word addressing */
604 return 4; // sizeof(DWORD)
606 else if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
608 /* Byte addressing */
609 return 1; // sizeof(BYTE)
613 /* Word addressing */
614 return 2; // sizeof(WORD)
618 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
620 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
623 /* Check for chain-4 and odd-even mode */
624 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
626 /* The lowest two bits are the plane number */
627 Plane
= Offset
& 0x03;
630 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
632 /* The LSB is the plane number */
633 Plane
= Offset
& 0x01;
638 /* Use the read mode */
639 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
642 /* Multiply the offset by the address size */
643 Offset
*= VgaGetAddressSize();
645 return Offset
+ Plane
* VGA_BANK_SIZE
;
648 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
650 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
652 /* Check for chain-4 and odd-even mode */
653 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
655 /* Shift the offset to the right by 2 */
658 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
660 /* Shift the offset to the right by 1 */
664 /* Multiply the offset by the address size */
665 Offset
*= VgaGetAddressSize();
667 /* Return the offset on plane 0 */
671 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
673 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 0x03;
674 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
678 /* In write mode 1 just return the latch register */
679 return VgaLatchRegisters
[Plane
];
684 /* Write modes 0 and 3 rotate the data to the right first */
685 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 0x07;
686 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
690 /* Write mode 2 expands the appropriate bit to all 8 bits */
691 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
697 * In write mode 0, the enable set/reset register decides if the
698 * set/reset bit should be expanded to all 8 bits.
700 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
702 /* Copy the bit from the set/reset register to all 8 bits */
703 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
709 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
710 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 0x03;
712 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
713 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
714 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
718 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
721 /* Then we expand the bit in the set/reset field */
722 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
725 /* Bits cleared in the bitmask are replaced with latch register bits */
726 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
728 /* Return the byte */
732 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
734 /* Check if this is the first time the rectangle is updated */
737 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
738 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
741 /* Expand the rectangle to include the point */
742 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
743 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
744 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
745 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
747 /* Set the update request flag */
751 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
755 /* Copy the colors of the default palette to the DAC and console palette */
756 for (i
= 0; i
< NumOfEntries
; i
++)
758 /* Set the palette entries */
759 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
760 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
761 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
762 Entries
[i
].peFlags
= 0;
764 /* Set the DAC registers */
765 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
766 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
767 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
771 static BOOLEAN
VgaInitializePalette(VOID
)
774 BOOLEAN Result
= FALSE
;
775 LPLOGPALETTE Palette
, TextPalette
;
777 /* Allocate storage space for the palettes */
778 Palette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
781 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
782 TextPalette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
785 (VGA_AC_PAL_F_REG
+ 1) * sizeof(PALETTEENTRY
));
786 if ((Palette
== NULL
) || (TextPalette
== NULL
)) goto Cleanup
;
788 /* Initialize the palettes */
789 Palette
->palVersion
= TextPalette
->palVersion
= 0x0300;
790 Palette
->palNumEntries
= VGA_MAX_COLORS
;
791 TextPalette
->palNumEntries
= VGA_AC_PAL_F_REG
+ 1;
793 /* Restore the default graphics palette */
794 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
796 /* Set the default text palette */
797 for (i
= 0; i
< TextPalette
->palNumEntries
; i
++)
799 /* Set the palette entries */
800 TextPalette
->palPalEntry
[i
].peRed
= GetRValue(ConsoleColors
[i
]);
801 TextPalette
->palPalEntry
[i
].peGreen
= GetGValue(ConsoleColors
[i
]);
802 TextPalette
->palPalEntry
[i
].peBlue
= GetBValue(ConsoleColors
[i
]);
803 TextPalette
->palPalEntry
[i
].peFlags
= 0;
806 /* Create the palettes */
807 PaletteHandle
= CreatePalette(Palette
);
808 TextPaletteHandle
= CreatePalette(TextPalette
);
810 if (PaletteHandle
!= NULL
&& TextPaletteHandle
!= NULL
)
812 /* The palettes have been created successfully */
817 /* Free the palettes */
818 if (Palette
) HeapFree(GetProcessHeap(), 0, Palette
);
819 if (TextPalette
) HeapFree(GetProcessHeap(), 0, TextPalette
);
823 /* Something failed, delete the palettes */
824 if (PaletteHandle
) DeleteObject(PaletteHandle
);
825 if (TextPaletteHandle
) DeleteObject(TextPaletteHandle
);
831 static VOID
VgaResetPalette(VOID
)
833 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
835 /* Restore the default palette */
836 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
837 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
838 PaletteChanged
= TRUE
;
841 static VOID
VgaSetActiveScreenBuffer(HANDLE ScreenBuffer
)
843 /* Set the active buffer */
844 SetConsoleActiveScreenBuffer(ScreenBuffer
);
846 /* Reinitialize the VDM menu */
848 CreateVdmMenu(ScreenBuffer
);
851 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
854 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
855 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
856 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
857 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
859 LONG Width
= Resolution
->X
;
860 LONG Height
= Resolution
->Y
;
862 /* Use DoubleVision mode if the resolution is too small */
863 DoubleWidth
= (Width
< VGA_MINIMUM_WIDTH
);
864 if (DoubleWidth
) Width
*= 2;
865 DoubleHeight
= (Height
< VGA_MINIMUM_HEIGHT
);
866 if (DoubleHeight
) Height
*= 2;
868 /* Fill the bitmap info header */
869 RtlZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BitmapInfo
->bmiHeader
));
870 BitmapInfo
->bmiHeader
.biSize
= sizeof(BitmapInfo
->bmiHeader
);
871 BitmapInfo
->bmiHeader
.biWidth
= Width
;
872 BitmapInfo
->bmiHeader
.biHeight
= Height
;
873 BitmapInfo
->bmiHeader
.biBitCount
= 8;
874 BitmapInfo
->bmiHeader
.biPlanes
= 1;
875 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
876 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
878 /* Fill the palette data */
879 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
881 /* Fill the console graphics buffer info */
882 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
883 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
884 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
886 /* Create the buffer */
887 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
888 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
890 CONSOLE_GRAPHICS_BUFFER
,
891 &GraphicsBufferInfo
);
892 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
894 /* Save the framebuffer address and mutex */
895 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
896 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
898 /* Clear the framebuffer */
899 RtlZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
901 /* Set the active buffer */
902 VgaSetActiveScreenBuffer(GraphicsConsoleBuffer
);
904 /* Set the graphics mode palette */
905 SetConsolePalette(GraphicsConsoleBuffer
,
909 /* Set the screen mode flag */
910 ScreenMode
= GRAPHICS_MODE
;
915 static VOID
VgaLeaveGraphicsMode(VOID
)
917 /* Release the console framebuffer mutex */
918 ReleaseMutex(ConsoleMutex
);
920 /* Switch back to the default console text buffer */
921 // VgaSetActiveScreenBuffer(TextConsoleBuffer);
923 /* Cleanup the video data */
924 CloseHandle(ConsoleMutex
);
926 ConsoleFramebuffer
= NULL
;
927 CloseHandle(GraphicsConsoleBuffer
);
928 GraphicsConsoleBuffer
= NULL
;
931 DoubleHeight
= FALSE
;
934 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
936 /* Switch to the text buffer */
937 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
939 /* Adjust the text framebuffer if we changed the resolution */
940 if (TextResolution
.X
!= Resolution
->X
||
941 TextResolution
.Y
!= Resolution
->Y
)
943 VgaDetachFromConsole(TRUE
);
946 * VgaAttachToConsoleInternal sets TextResolution to the
947 * new resolution and updates ConsoleInfo.
949 if (!VgaAttachToConsoleInternal(Resolution
))
951 DisplayMessage(L
"An unexpected error occurred!\n");
958 VgaUpdateCursorPosition();
961 /* The active framebuffer is now the text framebuffer */
962 ConsoleFramebuffer
= TextFramebuffer
;
965 * Set the text mode palette.
967 * WARNING: This call should fail on Windows (and therefore
968 * we get the default palette and our external behaviour is
969 * just like Windows' one), but it should success on ReactOS
970 * (so that we get console palette changes even for text-mode
971 * screen-buffers, which is a new feature on ReactOS).
973 SetConsolePalette(TextConsoleBuffer
,
977 /* Set the screen mode flag */
978 ScreenMode
= TEXT_MODE
;
983 static VOID
VgaLeaveTextMode(VOID
)
985 /* Reset the active framebuffer */
986 ConsoleFramebuffer
= NULL
;
989 static VOID
VgaChangeMode(VOID
)
991 COORD NewResolution
= VgaGetDisplayResolution();
992 SCREEN_MODE NewScreenMode
=
993 !(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) ? TEXT_MODE
997 * No need to switch to a different screen mode + resolution
998 * if the new ones are the same as the old ones.
1000 if ((ScreenMode
== NewScreenMode
) &&
1001 (CurrResolution
.X
== NewResolution
.X
&& CurrResolution
.Y
== NewResolution
.Y
))
1006 if (ScreenMode
== GRAPHICS_MODE
)
1008 /* Leave the current graphics mode */
1009 VgaLeaveGraphicsMode();
1013 /* Leave the current text mode */
1017 /* Update the current resolution */
1018 CurrResolution
= NewResolution
;
1020 /* The new screen mode will be updated via the VgaEnterText/GraphicsMode functions */
1022 /* Check if the new mode is alphanumeric */
1023 if (NewScreenMode
== TEXT_MODE
)
1025 /* Enter new text mode */
1026 if (!VgaEnterTextMode(&CurrResolution
))
1028 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
1029 EmulatorTerminate();
1035 /* Enter graphics mode */
1036 if (!VgaEnterGraphicsMode(&CurrResolution
))
1038 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
1039 EmulatorTerminate();
1046 /* Trigger a full update of the screen */
1048 UpdateRectangle
.Left
= 0;
1049 UpdateRectangle
.Top
= 0;
1050 UpdateRectangle
.Right
= CurrResolution
.X
;
1051 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
1053 /* Reset the mode change flag */
1054 ModeChanged
= FALSE
;
1057 static VOID
VgaUpdateFramebuffer(VOID
)
1060 DWORD AddressSize
= VgaGetAddressSize();
1061 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
1062 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
]);
1063 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1066 * If console framebuffer is NULL, that means something went wrong
1067 * earlier and this is the final display refresh.
1069 if (ConsoleFramebuffer
== NULL
) return;
1071 /* Check if we are in text or graphics mode */
1072 if (ScreenMode
== GRAPHICS_MODE
)
1075 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
1076 DWORD InterlaceHighBit
= VGA_INTERLACE_HIGH_BIT
;
1079 * Synchronize access to the graphics framebuffer
1080 * with the console framebuffer mutex.
1082 WaitForSingleObject(ConsoleMutex
, INFINITE
);
1084 /* Shift the high bit right by 1 in odd/even mode */
1085 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1087 InterlaceHighBit
>>= 1;
1090 /* Loop through the scanlines */
1091 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1093 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1095 /* Odd-numbered line in interlaced mode - set the high bit */
1096 Address
|= InterlaceHighBit
;
1099 /* Loop through the pixels */
1100 for (j
= 0; j
< CurrResolution
.X
; j
++)
1104 /* Check the shifting mode */
1105 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
1107 /* 4 bits shifted from each plane */
1109 /* Check if this is 16 or 256 color mode */
1110 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1112 /* One byte per pixel */
1113 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1114 + LOWORD((Address
+ (j
/ VGA_NUM_BANKS
))
1119 /* 4-bits per pixel */
1121 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1122 + LOWORD((Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1125 /* Check if we should use the highest 4 bits or lowest 4 */
1126 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
1138 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
1140 /* Check if this is 16 or 256 color mode */
1141 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1143 // TODO: NOT IMPLEMENTED
1144 DPRINT1("8-bit interleaved mode is not implemented!\n");
1149 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1150 * then 2 bits shifted from plane 1 and 3 for the next 4
1152 DWORD BankNumber
= (j
/ 4) % 2;
1153 DWORD Offset
= Address
+ (j
/ 8);
1154 BYTE LowPlaneData
= VgaMemory
[BankNumber
* VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
1155 BYTE HighPlaneData
= VgaMemory
[(BankNumber
+ 2) * VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
1157 /* Extract the two bits from each plane */
1158 LowPlaneData
= (LowPlaneData
>> (6 - ((j
% 4) * 2))) & 0x03;
1159 HighPlaneData
= (HighPlaneData
>> (6 - ((j
% 4) * 2))) & 0x03;
1161 /* Combine them into the pixel */
1162 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
1167 /* 1 bit shifted from each plane */
1169 /* Check if this is 16 or 256 color mode */
1170 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1172 /* 8 bits per pixel, 2 on each plane */
1174 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1176 /* The data is on plane k, 4 pixels per byte */
1177 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1178 + LOWORD((Address
+ (j
/ VGA_NUM_BANKS
))
1181 /* The mask of the first bit in the pair */
1182 BYTE BitMask
= 1 << (((3 - (j
% VGA_NUM_BANKS
)) * 2) + 1);
1184 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1185 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
1187 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1188 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
1193 /* 4 bits per pixel, 1 on each plane */
1195 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1197 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1198 + LOWORD((Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1201 /* If the bit on that plane is set, set it */
1202 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
1207 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
1210 * In 16 color mode, the value is an index to the AC registers
1211 * if external palette access is disabled, otherwise (in case
1212 * of palette loading) it is a blank pixel.
1214 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
1218 /* Take into account DoubleVision mode when checking for pixel updates */
1219 if (DoubleWidth
&& DoubleHeight
)
1221 /* Now check if the resulting pixel data has changed */
1222 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
1224 /* Yes, write the new value */
1225 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1226 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1227 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1228 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1230 /* Mark the specified pixel as changed */
1231 VgaMarkForUpdate(i
, j
);
1234 else if (DoubleWidth
&& !DoubleHeight
)
1236 /* Now check if the resulting pixel data has changed */
1237 if (GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
1239 /* Yes, write the new value */
1240 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1241 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1243 /* Mark the specified pixel as changed */
1244 VgaMarkForUpdate(i
, j
);
1247 else if (!DoubleWidth
&& DoubleHeight
)
1249 /* Now check if the resulting pixel data has changed */
1250 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] != PixelData
)
1252 /* Yes, write the new value */
1253 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] = PixelData
;
1254 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
) + j
] = PixelData
;
1256 /* Mark the specified pixel as changed */
1257 VgaMarkForUpdate(i
, j
);
1260 else // if (!DoubleWidth && !DoubleHeight)
1262 /* Now check if the resulting pixel data has changed */
1263 if (GraphicsBuffer
[i
* CurrResolution
.X
+ j
] != PixelData
)
1265 /* Yes, write the new value */
1266 GraphicsBuffer
[i
* CurrResolution
.X
+ j
] = PixelData
;
1268 /* Mark the specified pixel as changed */
1269 VgaMarkForUpdate(i
, j
);
1274 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1276 /* Clear the high bit */
1277 Address
&= ~InterlaceHighBit
;
1280 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) || (i
& 1))
1282 /* Move to the next scanline */
1283 Address
+= ScanlineSize
;
1288 * Release the console framebuffer mutex
1289 * so that we allow for repainting.
1291 ReleaseMutex(ConsoleMutex
);
1297 PCHAR_CELL CharBuffer
= (PCHAR_CELL
)ConsoleFramebuffer
;
1300 /* Loop through the scanlines */
1301 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1303 /* Loop through the characters */
1304 for (j
= 0; j
< CurrResolution
.X
; j
++)
1306 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1308 /* Plane 0 holds the character itself */
1309 CharInfo
.Char
= VgaMemory
[CurrentAddr
];
1311 /* Plane 1 holds the attribute */
1312 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
1314 /* Now check if the resulting character data has changed */
1315 if ((CharBuffer
[i
* CurrResolution
.X
+ j
].Char
!= CharInfo
.Char
) ||
1316 (CharBuffer
[i
* CurrResolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
1318 /* Yes, write the new value */
1319 CharBuffer
[i
* CurrResolution
.X
+ j
] = CharInfo
;
1321 /* Mark the specified cell as changed */
1322 VgaMarkForUpdate(i
, j
);
1326 /* Move to the next scanline */
1327 Address
+= ScanlineSize
;
1332 static VOID
VgaUpdateTextCursor(VOID
)
1335 CONSOLE_CURSOR_INFO CursorInfo
;
1337 BOOL CursorVisible
= !(VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x20);
1338 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x1F;
1339 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
1341 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1342 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1343 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
1344 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
1346 /* Just return if we are not in text mode */
1347 if (ScreenMode
!= TEXT_MODE
) return;
1349 if (CursorStart
< CursorEnd
)
1351 /* Visible cursor */
1352 CursorInfo
.bVisible
= CursorVisible
;
1353 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
1358 CursorInfo
.bVisible
= FALSE
;
1359 CursorInfo
.dwSize
= 1; // The size needs to be non-null in order SetConsoleCursorInfo to succeed.
1362 /* Add the cursor skew to the location */
1363 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 0x03;
1365 /* Find the coordinates of the new position */
1366 Position
.X
= (SHORT
)(Location
% ScanlineSize
);
1367 Position
.Y
= (SHORT
)(Location
/ ScanlineSize
);
1369 DPRINT("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position
.X
, Position
.Y
);
1371 /* Update the physical cursor */
1372 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
1373 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
1375 /* Reset the cursor changed flag */
1376 CursorChanged
= FALSE
;
1379 static BYTE WINAPI
VgaReadPort(USHORT Port
)
1381 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1386 return VgaMiscRegister
;
1388 case VGA_INSTAT0_READ
:
1389 return 0; // Not implemented
1391 case VGA_INSTAT1_READ_MONO
:
1392 case VGA_INSTAT1_READ_COLOR
:
1396 /* Reset the AC latch */
1399 /* Set a flag if there is a vertical or horizontal retrace */
1400 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
1402 /* Set an additional flag if there was a vertical retrace */
1403 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
1405 /* Clear the flags */
1406 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
1411 case VGA_FEATURE_READ
:
1412 return VgaFeatureRegister
;
1418 return VgaAcRegisters
[VgaAcIndex
];
1424 return VgaSeqRegisters
[VgaSeqIndex
];
1429 case VGA_DAC_READ_INDEX
:
1430 /* This returns the read/write state */
1431 return (VgaDacReadWrite
? 0 : 3);
1433 case VGA_DAC_WRITE_INDEX
:
1434 return (VgaDacIndex
/ 3);
1438 /* Ignore reads in write mode */
1439 if (!VgaDacReadWrite
)
1441 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
1442 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1449 case VGA_CRTC_INDEX_MONO
:
1450 case VGA_CRTC_INDEX_COLOR
:
1451 return VgaCrtcIndex
;
1453 case VGA_CRTC_DATA_MONO
:
1454 case VGA_CRTC_DATA_COLOR
:
1455 return VgaCrtcRegisters
[VgaCrtcIndex
];
1461 return VgaGcRegisters
[VgaGcIndex
];
1464 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1471 static inline VOID
VgaWriteSequencer(BYTE Data
)
1473 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
1475 /* Save the value */
1476 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
1479 static inline VOID
VgaWriteGc(BYTE Data
)
1481 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
1483 /* Save the value */
1484 VgaGcRegisters
[VgaGcIndex
] = Data
;
1486 /* Check the index */
1489 case VGA_GC_MISC_REG
:
1491 /* The GC misc register decides if it's text or graphics mode */
1498 static inline VOID
VgaWriteCrtc(BYTE Data
)
1500 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
1502 /* Save the value */
1503 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
1505 /* Check the index */
1506 switch (VgaCrtcIndex
)
1508 case VGA_CRTC_END_HORZ_DISP_REG
:
1509 case VGA_CRTC_VERT_DISP_END_REG
:
1510 case VGA_CRTC_OVERFLOW_REG
:
1511 case VGA_CRTC_MAX_SCAN_LINE_REG
:
1513 /* The video mode has changed */
1518 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
1519 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
1520 case VGA_CRTC_CURSOR_START_REG
:
1521 case VGA_CRTC_CURSOR_END_REG
:
1523 /* Set the cursor changed flag */
1524 CursorChanged
= TRUE
;
1530 static inline VOID
VgaWriteDac(BYTE Data
)
1532 INT i
, PaletteIndex
;
1536 VgaDacRegisters
[VgaDacIndex
] = Data
;
1538 /* Find the palette index */
1539 PaletteIndex
= VgaDacIndex
/ 3;
1541 /* Fill the entry structure */
1542 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3]);
1543 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 1]);
1544 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 2]);
1547 /* Update the palette entry */
1548 SetPaletteEntries(PaletteHandle
, PaletteIndex
, 1, &Entry
);
1550 /* Check which text palette entries are affected */
1551 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
1553 if (VgaAcRegisters
[i
] == PaletteIndex
)
1555 /* Update the text palette entry */
1556 SetPaletteEntries(TextPaletteHandle
, i
, 1, &Entry
);
1560 /* Set the palette changed flag */
1561 PaletteChanged
= TRUE
;
1563 /* Update the index */
1565 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1568 static inline VOID
VgaWriteAc(BYTE Data
)
1572 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
1574 /* Save the value */
1575 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
1577 if (VgaAcPalDisable
) return;
1579 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
1580 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
1582 /* Update the AC register */
1583 VgaAcRegisters
[VgaAcIndex
] = Data
;
1585 /* Fill the entry structure */
1586 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3]);
1587 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 1]);
1588 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 2]);
1591 /* Update the palette entry and set the palette change flag */
1592 SetPaletteEntries(TextPaletteHandle
, VgaAcIndex
, 1, &Entry
);
1593 PaletteChanged
= TRUE
;
1598 VgaAcRegisters
[VgaAcIndex
] = Data
;
1602 static VOID WINAPI
VgaWritePort(USHORT Port
, BYTE Data
)
1604 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1608 case VGA_MISC_WRITE
:
1610 VgaMiscRegister
= Data
;
1612 if (VgaMiscRegister
& 0x01)
1614 /* Color emulation */
1615 DPRINT1("Color emulation\n");
1617 /* Register the new I/O Ports */
1618 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1619 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1620 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1622 /* Unregister the old ones */
1623 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1624 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1625 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1629 /* Monochrome emulation */
1630 DPRINT1("Monochrome emulation\n");
1632 /* Register the new I/O Ports */
1633 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1634 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1635 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1637 /* Unregister the old ones */
1638 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1639 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1640 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1643 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1647 case VGA_FEATURE_WRITE_MONO
:
1648 case VGA_FEATURE_WRITE_COLOR
:
1650 VgaFeatureRegister
= Data
;
1655 // case VGA_AC_WRITE:
1659 /* Change the index */
1660 BYTE Index
= Data
& 0x1F;
1661 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1664 * Change palette protection by checking for
1665 * the Palette Address Source bit.
1667 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1671 /* Write the data */
1675 /* Toggle the latch */
1676 VgaAcLatch
= !VgaAcLatch
;
1682 /* Set the sequencer index register */
1683 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
1689 /* Call the sequencer function */
1690 VgaWriteSequencer(Data
);
1700 case VGA_DAC_READ_INDEX
:
1702 VgaDacReadWrite
= FALSE
;
1703 VgaDacIndex
= Data
* 3;
1707 case VGA_DAC_WRITE_INDEX
:
1709 VgaDacReadWrite
= TRUE
;
1710 VgaDacIndex
= Data
* 3;
1716 /* Ignore writes in read mode */
1717 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1721 case VGA_CRTC_INDEX_MONO
:
1722 case VGA_CRTC_INDEX_COLOR
:
1724 /* Set the CRTC index register */
1725 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
1729 case VGA_CRTC_DATA_MONO
:
1730 case VGA_CRTC_DATA_COLOR
:
1732 /* Call the CRTC function */
1739 /* Set the GC index register */
1740 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
1746 /* Call the GC function */
1752 DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port
, Data
);
1757 /* PUBLIC FUNCTIONS ***********************************************************/
1759 COORD
VgaGetDisplayResolution(VOID
)
1762 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1764 /* The low 8 bits are in the display registers */
1765 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
1766 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
1768 /* Set the top bits from the overflow register */
1769 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
1771 Resolution
.Y
|= 1 << 8;
1773 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
1775 Resolution
.Y
|= 1 << 9;
1778 /* Increase the values by 1 */
1782 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1784 /* Multiply the horizontal resolution by the 9/8 dot mode */
1785 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
1788 /* The horizontal resolution is halved in 8-bit mode */
1789 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
1792 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1794 /* Halve the vertical resolution */
1799 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1800 Resolution
.Y
/= MaximumScanLine
;
1803 /* Return the resolution */
1807 VOID
VgaRefreshDisplay(VOID
)
1809 HANDLE ConsoleBufferHandle
= NULL
;
1811 /* Set the vertical retrace flag */
1812 InVerticalRetrace
= TRUE
;
1814 /* If nothing has changed, just return */
1815 // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
1818 /* Change the display mode */
1819 if (ModeChanged
) VgaChangeMode();
1821 /* Change the text cursor appearance */
1822 if (CursorChanged
) VgaUpdateTextCursor();
1826 /* Trigger a full update of the screen */
1828 UpdateRectangle
.Left
= 0;
1829 UpdateRectangle
.Top
= 0;
1830 UpdateRectangle
.Right
= CurrResolution
.X
;
1831 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
1833 PaletteChanged
= FALSE
;
1836 /* Update the contents of the framebuffer */
1837 VgaUpdateFramebuffer();
1839 /* Ignore if there's nothing to update */
1840 if (!NeedsUpdate
) return;
1842 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1843 UpdateRectangle
.Left
,
1844 UpdateRectangle
.Top
,
1845 UpdateRectangle
.Right
,
1846 UpdateRectangle
.Bottom
);
1848 /* Check if we are in text or graphics mode */
1849 if (ScreenMode
== GRAPHICS_MODE
)
1852 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
1854 /* In DoubleVision mode, scale the update rectangle */
1857 UpdateRectangle
.Left
*= 2;
1858 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
1862 UpdateRectangle
.Top
*= 2;
1863 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
1869 ConsoleBufferHandle
= TextConsoleBuffer
;
1872 /* Redraw the screen */
1873 __InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
1875 /* Clear the update flag */
1876 NeedsUpdate
= FALSE
;
1879 VOID
VgaHorizontalRetrace(VOID
)
1882 InHorizontalRetrace
= TRUE
;
1885 VOID NTAPI
VgaReadMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
1889 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
1891 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1892 Address
= max(min(Address
, VgaGetVideoLimitAddress() - 1), VgaGetVideoBaseAddress());
1893 Size
= min(Size
, VgaGetVideoLimitAddress() - Address
+ 1);
1895 /* Ignore if video RAM access is disabled */
1896 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1898 /* Loop through each byte */
1899 for (i
= 0; i
< Size
; i
++)
1901 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1903 /* Copy the value to the buffer */
1904 BufPtr
[i
] = VgaMemory
[VideoAddress
];
1907 /* Load the latch registers */
1908 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1909 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1910 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1911 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1914 BOOLEAN NTAPI
VgaWriteMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
1918 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
1920 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1921 Address
= max(min(Address
, VgaGetVideoLimitAddress() - 1), VgaGetVideoBaseAddress());
1922 Size
= min(Size
, VgaGetVideoLimitAddress() - Address
+ 1);
1924 /* Ignore if video RAM access is disabled */
1925 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return TRUE
;
1927 /* Also ignore if write access to all planes is disabled */
1928 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return TRUE
;
1930 /* Loop through each byte */
1931 for (i
= 0; i
< Size
; i
++)
1933 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1935 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1937 /* Make sure the page is writeable */
1938 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1940 /* Check if this is chain-4 mode */
1941 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1943 if (((Address
+ i
) & 0x03) != j
)
1945 /* This plane will not be accessed */
1950 /* Check if this is odd-even mode */
1951 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1953 if (((Address
+ i
) & 0x01) != (j
& 1))
1955 /* This plane will not be accessed */
1960 /* Copy the value to the VGA memory */
1961 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(BufPtr
[i
], j
);
1968 VOID
VgaClearMemory(VOID
)
1970 RtlZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1973 VOID
VgaWriteFont(UINT FontNumber
, CONST UCHAR
* FontData
, UINT Height
)
1976 PUCHAR FontMemory
= (PUCHAR
)&VgaMemory
[VGA_BANK_SIZE
* VGA_FONT_BANK
+ (FontNumber
* VGA_FONT_SIZE
)];
1978 ASSERT(Height
<= VGA_MAX_FONT_HEIGHT
);
1980 for (i
= 0 ; i
< VGA_FONT_CHARACTERS
; i
++)
1982 /* Write the character */
1983 for (j
= 0; j
< Height
; j
++)
1985 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = FontData
[i
* Height
+ j
];
1988 /* Clear the unused part */
1989 for (j
= Height
; j
< VGA_MAX_FONT_HEIGHT
; j
++)
1991 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = 0;
1996 VOID
ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent
)
1998 DPRINT1("Screen events not handled\n");
2001 BOOL
VgaAttachToConsole(VOID
)
2004 // FIXME: We should go back to the saved screen state
2006 if (TextResolution
.X
== 0 || TextResolution
.Y
== 0)
2007 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
2009 if (TextResolution
.X
== 0) TextResolution
.X
= 80;
2010 if (TextResolution
.Y
== 0) TextResolution
.Y
= 25;
2012 return VgaAttachToConsoleInternal(&TextResolution
);
2015 VOID
VgaDetachFromConsole(BOOL ChangingMode
)
2019 COORD dummySize
= {0};
2022 // FIXME: We should save the screen state
2025 __RegisterConsoleVDM(0,
2037 TextFramebuffer
= NULL
;
2043 /* Restore the old screen buffer */
2044 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2046 /* Restore the original console size */
2049 ConRect
.Right
= ConRect
.Left
+ OrgConsoleBufferInfo
.srWindow
.Right
- OrgConsoleBufferInfo
.srWindow
.Left
;
2050 ConRect
.Bottom
= ConRect
.Top
+ OrgConsoleBufferInfo
.srWindow
.Bottom
- OrgConsoleBufferInfo
.srWindow
.Top
;
2052 * See the following trick explanation in VgaAttachToConsoleInternal.
2054 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
2055 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
2056 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
2058 /* Restore the original cursor shape */
2059 SetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
);
2063 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
2065 /* Save the default text-mode console output handle */
2066 if (!IsConsoleHandle(TextHandle
)) return FALSE
;
2067 TextConsoleBuffer
= TextHandle
;
2069 /* Save the original cursor and console screen buffer information */
2070 if (!GetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
) ||
2071 !GetConsoleScreenBufferInfo(TextConsoleBuffer
, &OrgConsoleBufferInfo
))
2075 ConsoleInfo
= OrgConsoleBufferInfo
;
2077 /* Initialize the VGA palette and fail if it isn't successfully created */
2078 if (!VgaInitializePalette()) return FALSE
;
2079 /***/ VgaResetPalette(); /***/
2081 /* Switch to the text buffer */
2082 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2084 /* Clear the VGA memory */
2087 /* Register the memory hook */
2088 MemInstallFastMemoryHook((PVOID
)0xA0000, 0x20000, VgaReadMemory
, VgaWriteMemory
);
2090 /* Register the I/O Ports */
2091 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
2092 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
2093 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
2094 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
2095 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
2096 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
2097 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
2098 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
2099 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
2100 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
2101 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
2102 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
2103 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
2105 /* CGA ports for compatibility, unimplemented */
2106 RegisterIoPort(0x3D8, VgaReadPort
, VgaWritePort
); // CGA_MODE_CTRL_REG
2107 RegisterIoPort(0x3D9, VgaReadPort
, VgaWritePort
); // CGA_PAL_CTRL_REG
2109 /* Return success */
2113 VOID
VgaCleanup(VOID
)
2115 if (ScreenMode
== GRAPHICS_MODE
)
2117 /* Leave the current graphics mode */
2118 VgaLeaveGraphicsMode();
2122 /* Leave the current text mode */
2126 VgaDetachFromConsole(FALSE
);
2127 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
2129 CloseHandle(AnotherEvent
);
2130 CloseHandle(EndEvent
);
2131 CloseHandle(StartEvent
);