2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: VGA hardware emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
15 #include "../bios/vidbios.h"
19 /* PRIVATE VARIABLES **********************************************************/
21 static CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
22 static CONST DWORD MemoryLimit
[] = { 0xAFFFF, 0xAFFFF, 0xB7FFF, 0xBFFFF };
25 * Activate this line if you want to use the real
26 * RegisterConsoleVDM API of Windows/ReactOS.
28 // #define USE_REAL_REGISTERCONSOLEVDM
30 #define USE_REACTOS_COLORS
31 // #define USE_DOSBOX_COLORS
33 #if defined(USE_REACTOS_COLORS)
36 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
38 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
39 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
40 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
41 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
42 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
43 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
44 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
45 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
46 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
47 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
48 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
49 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
50 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
51 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
52 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
53 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
54 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
55 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
56 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
57 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
58 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
59 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
60 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
61 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
62 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
63 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
64 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
65 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
66 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
67 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
68 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
69 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
70 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
71 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
72 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
73 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
74 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
75 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
76 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
77 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
78 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
79 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
80 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
81 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
82 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
83 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
84 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
85 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
86 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
87 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
88 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
89 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
90 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
91 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
92 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
93 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
94 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
95 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
96 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
97 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
98 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
99 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
100 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
101 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
104 #elif defined(USE_DOSBOX_COLORS)
107 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
109 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
110 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
111 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
112 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
113 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
114 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
115 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
116 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
117 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
118 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
119 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
120 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
121 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
122 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
123 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
124 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
126 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
127 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
128 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
129 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
130 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
131 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
132 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
133 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
134 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
135 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
136 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
137 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
138 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
139 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
140 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
141 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
143 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
144 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
145 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
146 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
147 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
148 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
149 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
150 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
151 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
152 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
153 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
154 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
155 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
156 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
157 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
158 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
160 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
161 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
162 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
163 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
164 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
165 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
166 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
167 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
168 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
169 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
170 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
171 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
172 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
173 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
174 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
175 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
181 * Default 16-color palette for foreground and background
182 * (corresponding flags in comments).
183 * Taken from subsystems/win32/winsrv/consrv/frontends/gui/conwnd.c
185 static const COLORREF ConsoleColors
[16] =
187 RGB(0, 0, 0), // (Black)
188 RGB(0, 0, 128), // BLUE
189 RGB(0, 128, 0), // GREEN
190 RGB(0, 128, 128), // BLUE | GREEN
191 RGB(128, 0, 0), // RED
192 RGB(128, 0, 128), // BLUE | RED
193 RGB(128, 128, 0), // GREEN | RED
194 RGB(192, 192, 192), // BLUE | GREEN | RED
196 RGB(128, 128, 128), // (Grey) INTENSITY
197 RGB(0, 0, 255), // BLUE | INTENSITY
198 RGB(0, 255, 0), // GREEN | INTENSITY
199 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
200 RGB(255, 0, 0), // RED | INTENSITY
201 RGB(255, 0, 255), // BLUE | RED | INTENSITY
202 RGB(255, 255, 0), // GREEN | RED | INTENSITY
203 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
207 * Console interface -- VGA-mode-agnostic
209 typedef struct _CHAR_CELL
213 } CHAR_CELL
, *PCHAR_CELL
;
214 C_ASSERT(sizeof(CHAR_CELL
) == 2);
216 static LPVOID ConsoleFramebuffer
= NULL
; // Active framebuffer, points to
217 // either TextFramebuffer or a valid
218 // graphics framebuffer.
219 static HPALETTE TextPaletteHandle
= NULL
;
220 static HPALETTE PaletteHandle
= NULL
;
222 static HANDLE StartEvent
= NULL
;
223 static HANDLE EndEvent
= NULL
;
224 static HANDLE AnotherEvent
= NULL
;
226 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo
;
227 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo
;
231 * Text mode -- we always keep a valid text mode framebuffer
232 * even if we are in graphics mode. This is needed in order to
233 * keep a consistent VGA state.
235 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
236 static COORD TextResolution
= {0};
237 static PCHAR_CELL TextFramebuffer
= NULL
;
238 static HANDLE TextConsoleBuffer
= NULL
;
241 static HANDLE GraphicsConsoleBuffer
= NULL
;
242 static HANDLE ConsoleMutex
= NULL
;
243 static BOOLEAN DoubleVision
= FALSE
;
248 static BYTE VgaMemory
[VGA_NUM_BANKS
* VGA_BANK_SIZE
];
250 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
252 static BYTE VgaMiscRegister
;
253 static BYTE VgaFeatureRegister
;
255 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
256 static BYTE VgaSeqRegisters
[VGA_SEQ_MAX_REG
];
258 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
259 static BYTE VgaCrtcRegisters
[VGA_CRTC_MAX_REG
];
261 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
262 static BYTE VgaGcRegisters
[VGA_GC_MAX_REG
];
264 static BOOLEAN VgaAcLatch
= FALSE
;
265 static BOOLEAN VgaAcPalDisable
= TRUE
;
266 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
267 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
269 // static VGA_REGISTERS VgaRegisters;
271 static BYTE VgaDacMask
= 0xFF;
272 static WORD VgaDacIndex
= 0;
273 static BOOLEAN VgaDacReadWrite
= FALSE
;
274 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
276 static BOOLEAN InVerticalRetrace
= FALSE
;
277 static BOOLEAN InHorizontalRetrace
= FALSE
;
279 static BOOLEAN NeedsUpdate
= FALSE
;
280 static BOOLEAN ModeChanged
= FALSE
;
281 static BOOLEAN CursorMoved
= FALSE
;
282 static BOOLEAN PaletteChanged
= FALSE
;
289 } ScreenMode
= TEXT_MODE
;
291 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
293 /* RegisterConsoleVDM EMULATION ***********************************************/
295 #include <ntddvdeo.h>
297 #ifdef USE_REAL_REGISTERCONSOLEVDM
299 #define __RegisterConsoleVDM RegisterConsoleVDM
300 #define __InvalidateConsoleDIBits InvalidateConsoleDIBits
305 * This private buffer, per-console, is used by
306 * RegisterConsoleVDM and InvalidateConsoleDIBits.
308 static COORD VDMBufferSize
= {0};
309 static PCHAR_CELL VDMBuffer
= NULL
;
311 static PCHAR_INFO CharBuff
= NULL
; // This is a hack, which is unneeded
312 // for the real RegisterConsoleVDM and
313 // InvalidateConsoleDIBits
317 __RegisterConsoleVDM(IN DWORD dwDosVDMFlag
,
318 IN HANDLE hEventHandle1
,
319 IN HANDLE hEventHandle2
,
320 IN HANDLE hEventHandle3
,
322 OUT PULONG returned_val_1
,
323 OUT PVOID
* returned_val_2
,
324 IN PVOID lpUnknownBuffer
,
325 IN DWORD dwUnknownBufferLength
,
326 IN COORD dwVDMBufferSize
,
327 OUT PVOID
* lpVDMBuffer
)
329 UNREFERENCED_PARAMETER(hEventHandle3
);
330 UNREFERENCED_PARAMETER(Unused1
);
331 UNREFERENCED_PARAMETER(returned_val_1
);
332 UNREFERENCED_PARAMETER(returned_val_2
);
333 UNREFERENCED_PARAMETER(lpUnknownBuffer
);
334 UNREFERENCED_PARAMETER(dwUnknownBufferLength
);
337 DPRINT1("__RegisterConsoleVDM(%d)\n", dwDosVDMFlag
);
339 if (lpVDMBuffer
== NULL
) return FALSE
;
341 if (dwDosVDMFlag
!= 0)
343 // if (EventHandle_1 == NULL || EventHandle_2 == NULL) return FALSE;
344 if (VDMBuffer
!= NULL
) return FALSE
;
346 VDMBufferSize
= dwVDMBufferSize
;
348 /* HACK: Cache -- to be removed in the real implementation */
349 CharBuff
= HeapAlloc(GetProcessHeap(),
351 VDMBufferSize
.X
* VDMBufferSize
.Y
352 * sizeof(CHAR_INFO
));
355 VDMBuffer
= HeapAlloc(GetProcessHeap(),
357 VDMBufferSize
.X
* VDMBufferSize
.Y
358 * sizeof(CHAR_CELL
));
359 *lpVDMBuffer
= VDMBuffer
;
360 return (VDMBuffer
!= NULL
);
364 /* HACK: Cache -- to be removed in the real implementation */
365 if (CharBuff
) HeapFree(GetProcessHeap(), 0, CharBuff
);
368 if (VDMBuffer
) HeapFree(GetProcessHeap(), 0, VDMBuffer
);
371 VDMBufferSize
.X
= VDMBufferSize
.Y
= 0;
378 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput
,
379 IN PSMALL_RECT lpRect
)
381 if ((hConsoleOutput
== TextConsoleBuffer
) && (VDMBuffer
!= NULL
))
383 /* HACK: Write the cached data to the console */
385 COORD Origin
= { lpRect
->Left
, lpRect
->Top
};
390 for (i
= 0; i
< VDMBufferSize
.Y
; i
++)
392 for (j
= 0; j
< VDMBufferSize
.X
; j
++)
394 CharBuff
[i
* VDMBufferSize
.X
+ j
].Char
.AsciiChar
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Char
;
395 CharBuff
[i
* VDMBufferSize
.X
+ j
].Attributes
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Attributes
;
399 WriteConsoleOutputA(hConsoleOutput
,
406 return InvalidateConsoleDIBits(hConsoleOutput
, lpRect
);
411 /* PRIVATE FUNCTIONS **********************************************************/
413 static inline DWORD
VgaGetAddressSize(VOID
);
414 static VOID
VgaUpdateTextCursor(VOID
);
416 static VOID
VgaUpdateCursorPosition(VOID
)
419 * Update the cursor position in the VGA registers.
421 WORD Offset
= ConsoleInfo
.dwCursorPosition
.Y
* TextResolution
.X
+
422 ConsoleInfo
.dwCursorPosition
.X
;
424 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
] = LOBYTE(Offset
);
425 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
] = HIBYTE(Offset
);
427 // VidBiosSyncCursorPosition();
428 VgaUpdateTextCursor();
431 static BOOL
VgaAttachToConsoleInternal(PCOORD Resolution
)
435 PVIDEO_HARDWARE_STATE_HEADER State
;
437 #ifdef USE_REAL_REGISTERCONSOLEVDM
438 PCHAR_INFO CharBuff
= NULL
;
441 DWORD AddressSize
, ScanlineSize
;
445 COORD Origin
= { 0, 0 };
447 ASSERT(TextFramebuffer
== NULL
);
449 TextResolution
= *Resolution
;
452 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
453 * in the two following APIs:
454 * SrvRegisterConsoleVDM (corresponding win32 API: RegisterConsoleVDM)
455 * SrvVDMConsoleOperation (corresponding Win32 API: )
456 * to check whether the current process is a VDM process, and fails otherwise with the
457 * error 0xC0000022 ().
459 * It is worth it to notice that also basesrv.dll does the same only for the
460 * BaseSrvIsFirstVDM API...
464 __RegisterConsoleVDM(1,
467 AnotherEvent
, // NULL,
469 &Length
, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
470 (PVOID
*)&State
, // NULL,
474 (PVOID
*)&TextFramebuffer
);
477 DisplayMessage(L
"RegisterConsoleVDM failed with error %d\n", GetLastError());
482 #ifdef USE_REAL_REGISTERCONSOLEVDM
483 CharBuff
= HeapAlloc(GetProcessHeap(),
485 TextResolution
.X
* TextResolution
.Y
486 * sizeof(CHAR_INFO
));
494 ConRect
.Top
= ConsoleInfo
.srWindow
.Top
;
495 ConRect
.Right
= ConRect
.Left
+ Resolution
->X
- 1;
496 ConRect
.Bottom
= ConRect
.Top
+ Resolution
->Y
- 1;
498 * Use this trick to effectively resize the console buffer and window,
500 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
501 * is smaller than the current console window size, and:
502 * - SetConsoleWindowInfo fails if the new console window size is larger
503 * than the current console screen buffer size.
505 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
506 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
507 SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
508 /* Update the saved console information */
509 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
512 * Copy console data into VGA memory
516 AddressSize
= VgaGetAddressSize();
517 ConRect
.Left
= ConRect
.Top
= 0;
518 ConRect
.Right
= TextResolution
.X
;
519 ConRect
.Bottom
= TextResolution
.Y
;
520 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
522 /* Read the data from the console into the framebuffer... */
523 ReadConsoleOutputA(TextConsoleBuffer
,
529 /* ... and copy the framebuffer into the VGA memory */
531 /* Loop through the scanlines */
532 for (i
= 0; i
< TextResolution
.Y
; i
++)
534 /* Loop through the characters */
535 for (j
= 0; j
< TextResolution
.X
; j
++)
537 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
539 /* Store the character in plane 0 */
540 VgaMemory
[CurrentAddr
] = CharBuff
[i
* TextResolution
.X
+ j
].Char
.AsciiChar
;
542 /* Store the attribute in plane 1 */
543 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuff
[i
* TextResolution
.X
+ j
].Attributes
;
546 /* Move to the next scanline */
547 Address
+= ScanlineSize
;
550 #ifdef USE_REAL_REGISTERCONSOLEVDM
551 if (CharBuff
) HeapFree(GetProcessHeap(), 0, CharBuff
);
554 VgaUpdateCursorPosition();
559 static BOOL
IsConsoleHandle(HANDLE hHandle
)
563 /* Check whether the handle may be that of a console... */
564 if ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) != FILE_TYPE_CHAR
)
568 * It may be. Perform another test... The idea comes from the
569 * MSDN description of the WriteConsole API:
571 * "WriteConsole fails if it is used with a standard handle
572 * that is redirected to a file. If an application processes
573 * multilingual output that can be redirected, determine whether
574 * the output handle is a console handle (one method is to call
575 * the GetConsoleMode function and check whether it succeeds).
576 * If the handle is a console handle, call WriteConsole. If the
577 * handle is not a console handle, the output is redirected and
578 * you should call WriteFile to perform the I/O."
580 return GetConsoleMode(hHandle
, &dwMode
);
583 static inline DWORD
VgaGetAddressSize(VOID
)
585 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
587 /* Double-word addressing */
588 return 4; // sizeof(DWORD)
590 else if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
592 /* Byte addressing */
593 return 1; // sizeof(BYTE)
597 /* Word addressing */
598 return 2; // sizeof(WORD)
602 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
604 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
607 /* Check for chain-4 and odd-even mode */
608 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
610 /* The lowest two bits are the plane number */
614 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
616 /* The LSB is the plane number */
622 /* Use the read mode */
623 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
626 /* Multiply the offset by the address size */
627 Offset
*= VgaGetAddressSize();
629 return Offset
+ Plane
* VGA_BANK_SIZE
;
632 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
634 DWORD Offset
= Address
- VgaGetVideoBaseAddress();
636 /* Check for chain-4 and odd-even mode */
637 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
639 /* Shift the offset to the right by 2 */
642 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
644 /* Shift the offset to the right by 1 */
648 /* Multiply the offset by the address size */
649 Offset
*= VgaGetAddressSize();
651 /* Return the offset on plane 0 */
655 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
657 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 3;
658 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
662 /* In write mode 1 just return the latch register */
663 return VgaLatchRegisters
[Plane
];
668 /* Write modes 0 and 3 rotate the data to the right first */
669 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 7;
670 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
674 /* Write mode 2 expands the appropriate bit to all 8 bits */
675 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
681 * In write mode 0, the enable set/reset register decides if the
682 * set/reset bit should be expanded to all 8 bits.
684 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
686 /* Copy the bit from the set/reset register to all 8 bits */
687 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
693 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
694 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 3;
696 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
697 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
698 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
702 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
705 /* Then we expand the bit in the set/reset field */
706 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
709 /* Bits cleared in the bitmask are replaced with latch register bits */
710 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
712 /* Return the byte */
716 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
718 /* Check if this is the first time the rectangle is updated */
721 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
722 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
725 /* Expand the rectangle to include the point */
726 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
727 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
728 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
729 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
731 /* Set the update request flag */
735 static VOID
VgaWriteSequencer(BYTE Data
)
737 ASSERT(VgaSeqIndex
< VGA_SEQ_MAX_REG
);
740 VgaSeqRegisters
[VgaSeqIndex
] = Data
;
743 static VOID
VgaWriteGc(BYTE Data
)
745 ASSERT(VgaGcIndex
< VGA_GC_MAX_REG
);
748 VgaGcRegisters
[VgaGcIndex
] = Data
;
750 /* Check the index */
753 case VGA_GC_MISC_REG
:
755 /* The GC misc register decides if it's text or graphics mode */
762 static VOID
VgaWriteCrtc(BYTE Data
)
764 ASSERT(VgaGcIndex
< VGA_CRTC_MAX_REG
);
767 VgaCrtcRegisters
[VgaCrtcIndex
] = Data
;
769 /* Check the index */
770 switch (VgaCrtcIndex
)
772 case VGA_CRTC_END_HORZ_DISP_REG
:
773 case VGA_CRTC_VERT_DISP_END_REG
:
774 case VGA_CRTC_OVERFLOW_REG
:
776 /* The video mode has changed */
781 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
782 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
783 case VGA_CRTC_CURSOR_START_REG
:
784 case VGA_CRTC_CURSOR_END_REG
:
786 /* Set the cursor moved flag */
793 static VOID
VgaWriteDac(BYTE Data
)
799 VgaDacRegisters
[VgaDacIndex
] = Data
;
801 /* Find the palette index */
802 PaletteIndex
= VgaDacIndex
/ 3;
804 /* Fill the entry structure */
805 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3]);
806 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 1]);
807 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[PaletteIndex
* 3 + 2]);
810 /* Update the palette entry */
811 SetPaletteEntries(PaletteHandle
, PaletteIndex
, 1, &Entry
);
813 /* Check which text palette entries are affected */
814 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
816 if (VgaAcRegisters
[i
] == PaletteIndex
)
818 /* Update the text palette entry */
819 SetPaletteEntries(TextPaletteHandle
, i
, 1, &Entry
);
823 /* Set the palette changed flag */
824 PaletteChanged
= TRUE
;
826 /* Update the index */
828 VgaDacIndex
%= VGA_PALETTE_SIZE
;
831 static VOID
VgaWriteAc(BYTE Data
)
835 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
838 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
840 if (VgaAcPalDisable
) return;
842 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
843 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
845 /* Update the AC register */
846 VgaAcRegisters
[VgaAcIndex
] = Data
;
848 /* Fill the entry structure */
849 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3]);
850 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 1]);
851 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 2]);
854 /* Update the palette entry and set the palette change flag */
855 SetPaletteEntries(TextPaletteHandle
, VgaAcIndex
, 1, &Entry
);
856 PaletteChanged
= TRUE
;
861 VgaAcRegisters
[VgaAcIndex
] = Data
;
865 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
869 /* Copy the colors of the default palette to the DAC and console palette */
870 for (i
= 0; i
< NumOfEntries
; i
++)
872 /* Set the palette entries */
873 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
874 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
875 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
876 Entries
[i
].peFlags
= 0;
878 /* Set the DAC registers */
879 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
880 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
881 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
885 static BOOLEAN
VgaInitializePalette(VOID
)
888 BOOLEAN Result
= FALSE
;
889 LPLOGPALETTE Palette
, TextPalette
;
891 /* Allocate storage space for the palettes */
892 Palette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
895 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
896 TextPalette
= (LPLOGPALETTE
)HeapAlloc(GetProcessHeap(),
899 (VGA_AC_PAL_F_REG
+ 1) * sizeof(PALETTEENTRY
));
900 if ((Palette
== NULL
) || (TextPalette
== NULL
)) goto Cleanup
;
902 /* Initialize the palettes */
903 Palette
->palVersion
= TextPalette
->palVersion
= 0x0300;
904 Palette
->palNumEntries
= VGA_MAX_COLORS
;
905 TextPalette
->palNumEntries
= VGA_AC_PAL_F_REG
+ 1;
907 /* Restore the default graphics palette */
908 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
910 /* Set the default text palette */
911 for (i
= 0; i
< TextPalette
->palNumEntries
; i
++)
913 /* Set the palette entries */
914 TextPalette
->palPalEntry
[i
].peRed
= GetRValue(ConsoleColors
[i
]);
915 TextPalette
->palPalEntry
[i
].peGreen
= GetGValue(ConsoleColors
[i
]);
916 TextPalette
->palPalEntry
[i
].peBlue
= GetBValue(ConsoleColors
[i
]);
917 TextPalette
->palPalEntry
[i
].peFlags
= 0;
920 /* Create the palettes */
921 PaletteHandle
= CreatePalette(Palette
);
922 TextPaletteHandle
= CreatePalette(TextPalette
);
924 if (PaletteHandle
!= NULL
&& TextPaletteHandle
!= NULL
)
926 /* The palettes have been created successfully */
931 /* Free the palettes */
932 if (Palette
) HeapFree(GetProcessHeap(), 0, Palette
);
933 if (TextPalette
) HeapFree(GetProcessHeap(), 0, TextPalette
);
937 /* Something failed, delete the palettes */
938 if (PaletteHandle
) DeleteObject(PaletteHandle
);
939 if (TextPaletteHandle
) DeleteObject(TextPaletteHandle
);
945 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
948 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
949 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
950 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
951 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
953 LONG Width
= Resolution
->X
;
954 LONG Height
= Resolution
->Y
;
956 /* Use DoubleVision mode if the resolution is too small */
957 if (Width
< VGA_MINIMUM_WIDTH
&& Height
< VGA_MINIMUM_HEIGHT
)
965 DoubleVision
= FALSE
;
968 /* Fill the bitmap info header */
969 ZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BITMAPINFOHEADER
));
970 BitmapInfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
971 BitmapInfo
->bmiHeader
.biWidth
= Width
;
972 BitmapInfo
->bmiHeader
.biHeight
= Height
;
973 BitmapInfo
->bmiHeader
.biBitCount
= 8;
974 BitmapInfo
->bmiHeader
.biPlanes
= 1;
975 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
976 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
978 /* Fill the palette data */
979 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
981 /* Fill the console graphics buffer info */
982 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
983 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
984 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
986 /* Create the buffer */
987 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
988 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
990 CONSOLE_GRAPHICS_BUFFER
,
991 &GraphicsBufferInfo
);
992 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
994 /* Save the framebuffer address and mutex */
995 ConsoleFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
996 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
998 /* Clear the framebuffer */
999 ZeroMemory(ConsoleFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
1001 /* Set the active buffer */
1002 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer
);
1004 /* Set the graphics mode palette */
1005 SetConsolePalette(GraphicsConsoleBuffer
,
1007 SYSPAL_NOSTATIC256
);
1009 /* Set the screen mode flag */
1010 ScreenMode
= GRAPHICS_MODE
;
1015 static VOID
VgaLeaveGraphicsMode(VOID
)
1017 /* Release the console framebuffer mutex */
1018 ReleaseMutex(ConsoleMutex
);
1020 /* Switch back to the default console text buffer */
1021 // SetConsoleActiveScreenBuffer(TextConsoleBuffer);
1023 /* Cleanup the video data */
1024 CloseHandle(ConsoleMutex
);
1025 ConsoleMutex
= NULL
;
1026 ConsoleFramebuffer
= NULL
;
1027 CloseHandle(GraphicsConsoleBuffer
);
1028 GraphicsConsoleBuffer
= NULL
;
1029 DoubleVision
= FALSE
;
1032 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
1034 DPRINT1("VgaEnterTextMode\n");
1036 /* Switch to the text buffer */
1037 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
1039 /* Adjust the text framebuffer if we changed the resolution */
1040 if (TextResolution
.X
!= Resolution
->X
||
1041 TextResolution
.Y
!= Resolution
->Y
)
1043 VgaDetachFromConsole(TRUE
);
1046 * VgaAttachToConsoleInternal sets TextResolution to the
1047 * new resolution and updates ConsoleInfo.
1049 if (!VgaAttachToConsoleInternal(Resolution
))
1051 DisplayMessage(L
"An unexpected error occurred!\n");
1052 EmulatorTerminate();
1058 VgaUpdateCursorPosition();
1061 /* The active framebuffer is now the text framebuffer */
1062 ConsoleFramebuffer
= TextFramebuffer
;
1065 * Set the text mode palette.
1067 * WARNING: This call should fail on Windows (and therefore
1068 * we get the default palette and our external behaviour is
1069 * just like Windows' one), but it should success on ReactOS
1070 * (so that we get console palette changes even for text-mode
1071 * screen-buffers, which is a new feature on ReactOS).
1073 SetConsolePalette(TextConsoleBuffer
,
1075 SYSPAL_NOSTATIC256
);
1077 /* Set the screen mode flag */
1078 ScreenMode
= TEXT_MODE
;
1083 static VOID
VgaLeaveTextMode(VOID
)
1085 /* Reset the active framebuffer */
1086 ConsoleFramebuffer
= NULL
;
1089 static VOID
VgaChangeMode(VOID
)
1091 COORD Resolution
= VgaGetDisplayResolution();
1093 if (ScreenMode
== GRAPHICS_MODE
)
1095 /* Leave the current graphics mode */
1096 VgaLeaveGraphicsMode();
1100 /* Leave the current text mode */
1104 /* Check if the new mode is alphanumeric */
1105 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
))
1107 /* Enter new text mode */
1108 if (!VgaEnterTextMode(&Resolution
))
1110 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode.");
1111 EmulatorTerminate();
1117 /* Enter graphics mode */
1118 if (!VgaEnterGraphicsMode(&Resolution
))
1120 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode.");
1121 EmulatorTerminate();
1126 /* Trigger a full update of the screen */
1128 UpdateRectangle
.Left
= 0;
1129 UpdateRectangle
.Top
= 0;
1130 UpdateRectangle
.Right
= Resolution
.X
;
1131 UpdateRectangle
.Bottom
= Resolution
.Y
;
1133 /* Reset the mode change flag */
1134 ModeChanged
= FALSE
;
1137 static VOID
VgaUpdateFramebuffer(VOID
)
1140 COORD Resolution
= VgaGetDisplayResolution();
1141 DWORD AddressSize
= VgaGetAddressSize();
1142 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
1143 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
]);
1144 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1147 * If console framebuffer is NULL, that means something went wrong
1148 * earlier and this is the final display refresh.
1150 if (ConsoleFramebuffer
== NULL
) return;
1152 /* Check if this is text mode or graphics mode */
1153 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1156 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
1157 DWORD InterlaceHighBit
= VGA_INTERLACE_HIGH_BIT
;
1160 * Synchronize access to the graphics framebuffer
1161 * with the console framebuffer mutex.
1163 WaitForSingleObject(ConsoleMutex
, INFINITE
);
1165 /* Shift the high bit right by 1 in odd/even mode */
1166 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1168 InterlaceHighBit
>>= 1;
1171 /* Loop through the scanlines */
1172 for (i
= 0; i
< Resolution
.Y
; i
++)
1174 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1176 /* Odd-numbered line in interlaced mode - set the high bit */
1177 Address
|= InterlaceHighBit
;
1180 /* Loop through the pixels */
1181 for (j
= 0; j
< Resolution
.X
; j
++)
1185 /* Check the shifting mode */
1186 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
1188 /* 4 bits shifted from each plane */
1190 /* Check if this is 16 or 256 color mode */
1191 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1193 /* One byte per pixel */
1194 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1195 + (Address
+ (j
/ VGA_NUM_BANKS
))
1200 /* 4-bits per pixel */
1202 PixelData
= VgaMemory
[(j
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1203 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1206 /* Check if we should use the highest 4 bits or lowest 4 */
1207 if (((j
/ VGA_NUM_BANKS
) % 2) == 0)
1219 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
1221 /* Check if this is 16 or 256 color mode */
1222 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1224 // TODO: NOT IMPLEMENTED
1225 DPRINT1("8-bit interleaved mode is not implemented!\n");
1230 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1231 * then 2 bits shifted from plane 1 and 3 for the next 4
1233 DWORD BankNumber
= (j
/ 4) % 2;
1234 DWORD Offset
= Address
+ (j
/ 8);
1235 BYTE LowPlaneData
= VgaMemory
[BankNumber
* VGA_BANK_SIZE
+ Offset
* AddressSize
];
1236 BYTE HighPlaneData
= VgaMemory
[(BankNumber
+ 2) * VGA_BANK_SIZE
+ Offset
* AddressSize
];
1238 /* Extract the two bits from each plane */
1239 LowPlaneData
= (LowPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
1240 HighPlaneData
= (HighPlaneData
>> (6 - ((j
% 4) * 2))) & 3;
1242 /* Combine them into the pixel */
1243 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
1248 /* 1 bit shifted from each plane */
1250 /* Check if this is 16 or 256 color mode */
1251 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1253 /* 8 bits per pixel, 2 on each plane */
1255 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1257 /* The data is on plane k, 4 pixels per byte */
1258 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1259 + (Address
+ (j
/ VGA_NUM_BANKS
))
1262 /* The mask of the first bit in the pair */
1263 BYTE BitMask
= 1 << (((3 - (j
% VGA_NUM_BANKS
)) * 2) + 1);
1265 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1266 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
1268 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1269 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
1274 /* 4 bits per pixel, 1 on each plane */
1276 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1278 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1279 + (Address
+ (j
/ (VGA_NUM_BANKS
* 2)))
1282 /* If the bit on that plane is set, set it */
1283 if (PlaneData
& (1 << (7 - (j
% 8)))) PixelData
|= 1 << k
;
1288 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
1291 * In 16 color mode, the value is an index to the AC registers
1292 * if external palette access is disabled, otherwise (in case
1293 * of palette loading) it is a blank pixel.
1295 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
1299 /* Take into account DoubleVision mode when checking for pixel updates */
1302 /* Now check if the resulting pixel data has changed */
1303 if (GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] != PixelData
)
1305 /* Yes, write the new value */
1306 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2)] = PixelData
;
1307 GraphicsBuffer
[(i
* Resolution
.X
* 4) + (j
* 2 + 1)] = PixelData
;
1308 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2)] = PixelData
;
1309 GraphicsBuffer
[((i
* 2 + 1) * Resolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1311 /* Mark the specified pixel as changed */
1312 VgaMarkForUpdate(i
, j
);
1317 /* Now check if the resulting pixel data has changed */
1318 if (GraphicsBuffer
[i
* Resolution
.X
+ j
] != PixelData
)
1320 /* Yes, write the new value */
1321 GraphicsBuffer
[i
* Resolution
.X
+ j
] = PixelData
;
1323 /* Mark the specified pixel as changed */
1324 VgaMarkForUpdate(i
, j
);
1329 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1331 /* Clear the high bit */
1332 Address
&= ~InterlaceHighBit
;
1335 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) || (i
& 1))
1337 /* Move to the next scanline */
1338 Address
+= ScanlineSize
;
1343 * Release the console framebuffer mutex
1344 * so that we allow for repainting.
1346 ReleaseMutex(ConsoleMutex
);
1352 PCHAR_CELL CharBuffer
= (PCHAR_CELL
)ConsoleFramebuffer
;
1355 /* Loop through the scanlines */
1356 for (i
= 0; i
< Resolution
.Y
; i
++)
1358 /* Loop through the characters */
1359 for (j
= 0; j
< Resolution
.X
; j
++)
1361 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1363 /* Plane 0 holds the character itself */
1364 CharInfo
.Char
= VgaMemory
[CurrentAddr
];
1366 /* Plane 1 holds the attribute */
1367 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
1369 /* Now check if the resulting character data has changed */
1370 if ((CharBuffer
[i
* Resolution
.X
+ j
].Char
!= CharInfo
.Char
) ||
1371 (CharBuffer
[i
* Resolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
1373 /* Yes, write the new value */
1374 CharBuffer
[i
* Resolution
.X
+ j
] = CharInfo
;
1376 /* Mark the specified cell as changed */
1377 VgaMarkForUpdate(i
, j
);
1381 /* Move to the next scanline */
1382 Address
+= ScanlineSize
;
1387 static VOID
VgaUpdateTextCursor(VOID
)
1390 CONSOLE_CURSOR_INFO CursorInfo
;
1391 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x3F;
1392 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
1393 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1394 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1395 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
1396 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
1398 /* Just return if we are not in text mode */
1399 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) return;
1401 if (CursorStart
< CursorEnd
)
1403 /* Visible cursor */
1404 CursorInfo
.bVisible
= TRUE
;
1405 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
1410 CursorInfo
.bVisible
= FALSE
;
1411 CursorInfo
.dwSize
= 0;
1414 /* Add the cursor skew to the location */
1415 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 3;
1417 /* Find the coordinates of the new position */
1418 Position
.X
= (SHORT
)(Location
% ScanlineSize
);
1419 Position
.Y
= (SHORT
)(Location
/ ScanlineSize
);
1421 DPRINT1("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position
.X
, Position
.Y
);
1423 /* Update the physical cursor */
1424 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
1425 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
1427 /* Reset the cursor move flag */
1428 CursorMoved
= FALSE
;
1431 static BYTE WINAPI
VgaReadPort(ULONG Port
)
1433 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1438 return VgaMiscRegister
;
1440 case VGA_INSTAT0_READ
:
1441 return 0; // Not implemented
1443 case VGA_INSTAT1_READ_MONO
:
1444 case VGA_INSTAT1_READ_COLOR
:
1448 /* Reset the AC latch */
1451 /* Set a flag if there is a vertical or horizontal retrace */
1452 if (InVerticalRetrace
|| InHorizontalRetrace
) Result
|= VGA_STAT_DD
;
1454 /* Set an additional flag if there was a vertical retrace */
1455 if (InVerticalRetrace
) Result
|= VGA_STAT_VRETRACE
;
1457 /* Clear the flags */
1458 InHorizontalRetrace
= InVerticalRetrace
= FALSE
;
1463 case VGA_FEATURE_READ
:
1464 return VgaFeatureRegister
;
1470 return VgaAcRegisters
[VgaAcIndex
];
1476 return VgaSeqRegisters
[VgaSeqIndex
];
1481 case VGA_DAC_READ_INDEX
:
1482 /* This returns the read/write state */
1483 return (VgaDacReadWrite
? 0 : 3);
1485 case VGA_DAC_WRITE_INDEX
:
1486 return (VgaDacIndex
/ 3);
1490 /* Ignore reads in write mode */
1491 if (!VgaDacReadWrite
)
1493 BYTE Data
= VgaDacRegisters
[VgaDacIndex
++];
1494 VgaDacIndex
%= VGA_PALETTE_SIZE
;
1501 case VGA_CRTC_INDEX_MONO
:
1502 case VGA_CRTC_INDEX_COLOR
:
1503 return VgaCrtcIndex
;
1505 case VGA_CRTC_DATA_MONO
:
1506 case VGA_CRTC_DATA_COLOR
:
1507 return VgaCrtcRegisters
[VgaCrtcIndex
];
1513 return VgaGcRegisters
[VgaGcIndex
];
1516 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1523 static VOID WINAPI
VgaWritePort(ULONG Port
, BYTE Data
)
1525 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1529 case VGA_MISC_WRITE
:
1531 VgaMiscRegister
= Data
;
1533 if (VgaMiscRegister
& 0x01)
1535 /* Color emulation */
1536 DPRINT1("Color emulation\n");
1538 /* Register the new I/O Ports */
1539 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1540 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1541 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1543 /* Unregister the old ones */
1544 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1545 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1546 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1550 /* Monochrome emulation */
1551 DPRINT1("Monochrome emulation\n");
1553 /* Register the new I/O Ports */
1554 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1555 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1556 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1558 /* Unregister the old ones */
1559 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1560 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1561 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1564 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1568 case VGA_FEATURE_WRITE_MONO
:
1569 case VGA_FEATURE_WRITE_COLOR
:
1571 VgaFeatureRegister
= Data
;
1576 // case VGA_AC_WRITE:
1580 /* Change the index */
1581 BYTE Index
= Data
& 0x1F;
1582 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1585 * Change palette protection by checking for
1586 * the Palette Address Source bit.
1588 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1592 /* Write the data */
1596 /* Toggle the latch */
1597 VgaAcLatch
= !VgaAcLatch
;
1603 /* Set the sequencer index register */
1604 if (Data
< VGA_SEQ_MAX_REG
) VgaSeqIndex
= Data
;
1610 /* Call the sequencer function */
1611 VgaWriteSequencer(Data
);
1621 case VGA_DAC_READ_INDEX
:
1623 VgaDacReadWrite
= FALSE
;
1624 VgaDacIndex
= Data
* 3;
1628 case VGA_DAC_WRITE_INDEX
:
1630 VgaDacReadWrite
= TRUE
;
1631 VgaDacIndex
= Data
* 3;
1637 /* Ignore writes in read mode */
1638 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1642 case VGA_CRTC_INDEX_MONO
:
1643 case VGA_CRTC_INDEX_COLOR
:
1645 /* Set the CRTC index register */
1646 if (Data
< VGA_CRTC_MAX_REG
) VgaCrtcIndex
= Data
;
1650 case VGA_CRTC_DATA_MONO
:
1651 case VGA_CRTC_DATA_COLOR
:
1653 /* Call the CRTC function */
1660 /* Set the GC index register */
1661 if (Data
< VGA_GC_MAX_REG
) VgaGcIndex
= Data
;
1667 /* Call the GC function */
1673 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port
);
1678 /* PUBLIC FUNCTIONS ***********************************************************/
1680 DWORD
VgaGetVideoBaseAddress(VOID
)
1682 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1685 DWORD
VgaGetVideoLimitAddress(VOID
)
1687 return MemoryLimit
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
1690 COORD
VgaGetDisplayResolution(VOID
)
1693 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1695 /* The low 8 bits are in the display registers */
1696 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
1697 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
1699 /* Set the top bits from the overflow register */
1700 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
1702 Resolution
.Y
|= 1 << 8;
1704 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
1706 Resolution
.Y
|= 1 << 9;
1709 /* Increase the values by 1 */
1713 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1715 /* Multiply the horizontal resolution by the 9/8 dot mode */
1716 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
1719 /* The horizontal resolution is halved in 8-bit mode */
1720 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
1723 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
1725 /* Halve the vertical resolution */
1730 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1731 Resolution
.Y
/= MaximumScanLine
;
1734 /* Return the resolution */
1738 VOID
VgaRefreshDisplay(VOID
)
1740 HANDLE ConsoleBufferHandle
= NULL
;
1743 /* Set the vertical retrace flag */
1744 InVerticalRetrace
= TRUE
;
1746 /* If nothing has changed, just return */
1747 // if (!ModeChanged && !CursorMoved && !PaletteChanged && !NeedsUpdate)
1750 /* Change the display mode */
1751 if (ModeChanged
) VgaChangeMode();
1753 /* Change the text cursor location */
1754 if (CursorMoved
) VgaUpdateTextCursor();
1756 /* Retrieve the current resolution */
1757 Resolution
= VgaGetDisplayResolution();
1761 /* Trigger a full update of the screen */
1763 UpdateRectangle
.Left
= 0;
1764 UpdateRectangle
.Top
= 0;
1765 UpdateRectangle
.Right
= Resolution
.X
;
1766 UpdateRectangle
.Bottom
= Resolution
.Y
;
1768 PaletteChanged
= FALSE
;
1771 /* Update the contents of the framebuffer */
1772 VgaUpdateFramebuffer();
1774 /* Ignore if there's nothing to update */
1775 if (!NeedsUpdate
) return;
1777 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1778 UpdateRectangle
.Left
,
1779 UpdateRectangle
.Top
,
1780 UpdateRectangle
.Right
,
1781 UpdateRectangle
.Bottom
);
1783 /* Check if this is text mode or graphics mode */
1784 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
1787 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
1789 /* In DoubleVision mode, scale the update rectangle */
1792 UpdateRectangle
.Left
*= 2;
1793 UpdateRectangle
.Top
*= 2;
1794 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
1795 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
1801 ConsoleBufferHandle
= TextConsoleBuffer
;
1804 /* Redraw the screen */
1805 __InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
1807 /* Clear the update flag */
1808 NeedsUpdate
= FALSE
;
1811 VOID
VgaHorizontalRetrace(VOID
)
1814 InHorizontalRetrace
= TRUE
;
1817 VOID
VgaReadMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1822 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1824 /* Ignore if video RAM access is disabled */
1825 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1827 /* Loop through each byte */
1828 for (i
= 0; i
< Size
; i
++)
1830 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
1832 /* Load the latch registers */
1833 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
1834 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
1835 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1836 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
1838 /* Copy the value to the buffer */
1839 Buffer
[i
] = VgaMemory
[VideoAddress
];
1843 VOID
VgaWriteMemory(DWORD Address
, LPBYTE Buffer
, DWORD Size
)
1848 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
1850 /* Ignore if video RAM access is disabled */
1851 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
1853 /* Also ignore if write access to all planes is disabled */
1854 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return;
1856 /* Loop through each byte */
1857 for (i
= 0; i
< Size
; i
++)
1859 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
1861 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
1863 /* Make sure the page is writeable */
1864 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
1866 /* Check if this is chain-4 mode */
1867 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
1869 if (((Address
+ i
) & 3) != j
)
1871 /* This plane will not be accessed */
1876 /* Check if this is odd-even mode */
1877 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1879 if (((Address
+ i
) & 1) != (j
& 1))
1881 /* This plane will not be accessed */
1886 /* Copy the value to the VGA memory */
1887 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(Buffer
[i
], j
);
1892 VOID
VgaClearMemory(VOID
)
1894 ZeroMemory(VgaMemory
, sizeof(VgaMemory
));
1897 VOID
VgaResetPalette(VOID
)
1899 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
1901 /* Restore the default palette */
1902 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
1903 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
1904 PaletteChanged
= TRUE
;
1910 BOOL
VgaAttachToConsole(VOID
)
1913 // FIXME: We should go back to the saved screen state
1915 if (TextResolution
.X
== 0 || TextResolution
.Y
== 0)
1916 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
1918 if (TextResolution
.X
== 0) TextResolution
.X
= 80;
1919 if (TextResolution
.Y
== 0) TextResolution
.Y
= 25;
1921 return VgaAttachToConsoleInternal(&TextResolution
);
1924 VOID
VgaDetachFromConsole(BOOL ChangingMode
)
1928 COORD dummySize
= {0};
1931 // FIXME: We should save the screen state
1934 __RegisterConsoleVDM(0,
1946 TextFramebuffer
= NULL
;
1952 /* Restore the old screen buffer */
1953 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
1955 /* Restore the original console size */
1958 ConRect
.Right
= ConRect
.Left
+ OrgConsoleBufferInfo
.srWindow
.Right
- OrgConsoleBufferInfo
.srWindow
.Left
;
1959 ConRect
.Bottom
= ConRect
.Top
+ OrgConsoleBufferInfo
.srWindow
.Bottom
- OrgConsoleBufferInfo
.srWindow
.Top
;
1961 * See the following trick explanation in VgaAttachToConsoleInternal.
1963 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
1964 SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
1965 SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
1967 /* Restore the original cursor shape */
1968 SetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
);
1972 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
1974 /* Save the default text-mode console output handle */
1975 if (!IsConsoleHandle(TextHandle
)) return FALSE
;
1976 TextConsoleBuffer
= TextHandle
;
1978 /* Save the original cursor and console screen buffer information */
1979 if (!GetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
) ||
1980 !GetConsoleScreenBufferInfo(TextConsoleBuffer
, &OrgConsoleBufferInfo
))
1984 ConsoleInfo
= OrgConsoleBufferInfo
;
1986 /* Initialize the VGA palette and fail if it isn't successfully created */
1987 if (!VgaInitializePalette()) return FALSE
;
1988 /***/ VgaResetPalette(); /***/
1990 /* Switch to the text buffer */
1991 SetConsoleActiveScreenBuffer(TextConsoleBuffer
);
1993 /* Clear the VGA memory */
1996 /* Register the I/O Ports */
1997 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
1998 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
1999 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
2000 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
2001 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
2002 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
2003 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
2004 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
2005 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
2006 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
2007 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
2008 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
2009 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
2011 /* Return success */
2015 VOID
VgaCleanup(VOID
)
2017 if (ScreenMode
== GRAPHICS_MODE
)
2019 /* Leave the current graphics mode */
2020 VgaLeaveGraphicsMode();
2024 /* Leave the current text mode */
2028 VgaDetachFromConsole(FALSE
);
2030 CloseHandle(AnotherEvent
);
2031 CloseHandle(EndEvent
);
2032 CloseHandle(StartEvent
);