2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/hardware/video/svga.c
5 * PURPOSE: SuperVGA hardware emulation (Cirrus Logic CL-GD5434 compatible)
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
14 /* PRIVATE VARIABLES **********************************************************/
16 static CONST DWORD MemoryBase
[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
17 static CONST DWORD MemorySize
[] = { 0x20000, 0x10000, 0x08000, 0x08000 };
20 * Activate this line if you want to use the real
21 * RegisterConsoleVDM API of ReactOS/Windows.
23 // #define USE_REAL_REGISTERCONSOLEVDM
25 #define USE_REACTOS_COLORS
26 // #define USE_DOSBOX_COLORS
28 #if defined(USE_REACTOS_COLORS)
31 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
33 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
34 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
35 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
36 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
37 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
38 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
39 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
40 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
41 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
42 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
43 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
44 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
45 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
46 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
47 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
48 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
49 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
50 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
51 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
52 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
53 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
54 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
55 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
56 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
57 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
58 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
59 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
60 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
61 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
62 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
63 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
64 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
65 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
66 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
67 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
68 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
69 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
70 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
71 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
72 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
73 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
74 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
75 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
76 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
77 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
78 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
79 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
80 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
81 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
82 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
83 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
84 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
85 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
86 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
87 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
88 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
89 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
90 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
91 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
92 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
93 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
94 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
95 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
96 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
99 #elif defined(USE_DOSBOX_COLORS)
102 static CONST COLORREF VgaDefaultPalette
[VGA_MAX_COLORS
] =
104 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
105 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
106 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
107 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
108 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
109 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
110 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
111 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
112 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
113 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
114 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
115 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
116 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
117 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
118 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
119 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
121 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
122 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
123 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
124 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
125 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
126 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
127 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
128 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
129 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
130 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
131 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
132 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
133 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
134 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
135 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
136 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
138 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
139 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
140 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
141 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
142 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
143 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
144 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
145 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
146 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
147 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
148 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
149 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
150 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
151 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
152 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
153 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
155 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
156 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
157 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
158 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
159 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
160 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
161 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
162 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
163 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
164 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
165 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
166 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
167 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
168 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
169 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
170 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
176 * Default 16-color palette for foreground and background
177 * (corresponding flags in comments).
178 * Taken from subsystems/win32/winsrv/consrv/frontends/gui/conwnd.c
180 static const COLORREF ConsoleColors
[16] =
182 RGB(0, 0, 0), // (Black)
183 RGB(0, 0, 128), // BLUE
184 RGB(0, 128, 0), // GREEN
185 RGB(0, 128, 128), // BLUE | GREEN
186 RGB(128, 0, 0), // RED
187 RGB(128, 0, 128), // BLUE | RED
188 RGB(128, 128, 0), // GREEN | RED
189 RGB(192, 192, 192), // BLUE | GREEN | RED
191 RGB(128, 128, 128), // (Grey) INTENSITY
192 RGB(0, 0, 255), // BLUE | INTENSITY
193 RGB(0, 255, 0), // GREEN | INTENSITY
194 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
195 RGB(255, 0, 0), // RED | INTENSITY
196 RGB(255, 0, 255), // BLUE | RED | INTENSITY
197 RGB(255, 255, 0), // GREEN | RED | INTENSITY
198 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
202 * Console interface -- VGA-mode-agnostic
204 // WARNING! This structure *MUST BE* in sync with the one in consrv/include/conio_winsrv.h
205 typedef struct _CHAR_CELL
209 } CHAR_CELL
, *PCHAR_CELL
;
210 C_ASSERT(sizeof(CHAR_CELL
) == 2);
212 static PVOID ConsoleFramebuffer
= NULL
; // Active framebuffer, points to
213 // either TextFramebuffer or a
214 // valid graphics framebuffer.
215 static HPALETTE TextPaletteHandle
= NULL
;
216 static HPALETTE PaletteHandle
= NULL
;
218 static HANDLE StartEvent
= NULL
;
219 static HANDLE EndEvent
= NULL
;
220 static HANDLE AnotherEvent
= NULL
;
222 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo
;
223 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo
;
226 static HANDLE ScreenBufferHandle
= NULL
;
227 static PVOID OldConsoleFramebuffer
= NULL
;
231 * Text mode -- we always keep a valid text mode framebuffer
232 * even if we are in graphics mode. This is needed in order
233 * to keep a consistent VGA state. However, each time the VGA
234 * detaches from the console (and reattaches to it later on),
235 * this text mode framebuffer is recreated.
237 static HANDLE TextConsoleBuffer
= NULL
;
238 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
239 static COORD TextResolution
= {0};
240 static PCHAR_CELL TextFramebuffer
= NULL
;
245 static HANDLE GraphicsConsoleBuffer
= NULL
;
246 static PVOID GraphicsFramebuffer
= NULL
;
247 static HANDLE ConsoleMutex
= NULL
;
248 /* DoubleVision support */
249 static BOOLEAN DoubleWidth
= FALSE
;
250 static BOOLEAN DoubleHeight
= FALSE
;
256 static BYTE VgaMemory
[VGA_NUM_BANKS
* SVGA_BANK_SIZE
];
258 static BYTE VgaLatchRegisters
[VGA_NUM_BANKS
] = {0, 0, 0, 0};
260 static BYTE VgaMiscRegister
;
261 static BYTE VgaFeatureRegister
;
263 static BYTE VgaSeqIndex
= VGA_SEQ_RESET_REG
;
264 static BYTE VgaSeqRegisters
[SVGA_SEQ_MAX_REG
];
266 static BYTE VgaCrtcIndex
= VGA_CRTC_HORZ_TOTAL_REG
;
267 static BYTE VgaCrtcRegisters
[SVGA_CRTC_MAX_REG
];
269 static BYTE VgaGcIndex
= VGA_GC_RESET_REG
;
270 static BYTE VgaGcRegisters
[SVGA_GC_MAX_REG
];
272 static BOOLEAN VgaAcLatch
= FALSE
;
273 static BOOLEAN VgaAcPalDisable
= TRUE
;
274 static BYTE VgaAcIndex
= VGA_AC_PAL_0_REG
;
275 static BYTE VgaAcRegisters
[VGA_AC_MAX_REG
];
277 static BYTE VgaDacMask
= 0xFF;
278 static BYTE VgaDacLatchCounter
= 0;
279 static BYTE VgaDacLatch
[3];
281 static BOOLEAN VgaDacReadWrite
= FALSE
;
282 static WORD VgaDacIndex
= 0;
283 static BYTE VgaDacRegisters
[VGA_PALETTE_SIZE
];
285 // static VGA_REGISTERS VgaRegisters;
287 static ULONGLONG VerticalRetraceCycle
= 0ULL;
288 static ULONGLONG HorizontalRetraceCycle
= 0ULL;
289 static PHARDWARE_TIMER VSyncTimer
;
290 static PHARDWARE_TIMER HSyncTimer
;
292 static BOOLEAN NeedsUpdate
= FALSE
;
293 static BOOLEAN ModeChanged
= FALSE
;
294 static BOOLEAN CursorChanged
= FALSE
;
295 static BOOLEAN PaletteChanged
= FALSE
;
297 static UINT SvgaHdrCounter
= 0;
298 static BYTE SvgaHiddenRegister
= 0;
300 typedef enum _SCREEN_MODE
304 } SCREEN_MODE
, *PSCREEN_MODE
;
306 static SCREEN_MODE ScreenMode
= TEXT_MODE
;
307 static COORD CurrResolution
= {0};
309 static SMALL_RECT UpdateRectangle
= { 0, 0, 0, 0 };
311 /* RegisterConsoleVDM EMULATION ***********************************************/
313 #include <ntddvdeo.h>
315 #ifdef USE_REAL_REGISTERCONSOLEVDM
317 #define __RegisterConsoleVDM RegisterConsoleVDM
318 #define __InvalidateConsoleDIBits InvalidateConsoleDIBits
323 * This private buffer, per-console, is used by
324 * RegisterConsoleVDM and InvalidateConsoleDIBits.
326 static COORD VDMBufferSize
= {0};
327 static PCHAR_CELL VDMBuffer
= NULL
;
329 static PCHAR_INFO CharBuff
= NULL
; // This is a hack, which is unneeded
330 // for the real RegisterConsoleVDM and
331 // InvalidateConsoleDIBits
335 __RegisterConsoleVDM(IN DWORD dwRegisterFlags
,
336 IN HANDLE hStartHardwareEvent
,
337 IN HANDLE hEndHardwareEvent
,
338 IN HANDLE hErrorHardwareEvent
,
339 IN DWORD dwUnusedVar
,
340 OUT LPDWORD lpVideoStateLength
,
341 OUT PVOID
* lpVideoState
, // PVIDEO_HARDWARE_STATE_HEADER*
342 IN PVOID lpUnusedBuffer
,
343 IN DWORD dwUnusedBufferLength
,
344 IN COORD dwVDMBufferSize
,
345 OUT PVOID
* lpVDMBuffer
)
347 UNREFERENCED_PARAMETER(hErrorHardwareEvent
);
348 UNREFERENCED_PARAMETER(dwUnusedVar
);
349 UNREFERENCED_PARAMETER(lpVideoStateLength
);
350 UNREFERENCED_PARAMETER(lpVideoState
);
351 UNREFERENCED_PARAMETER(lpUnusedBuffer
);
352 UNREFERENCED_PARAMETER(dwUnusedBufferLength
);
355 DPRINT1("__RegisterConsoleVDM(%d)\n", dwRegisterFlags
);
357 if (lpVDMBuffer
== NULL
) return FALSE
;
359 if (dwRegisterFlags
!= 0)
361 // if (hStartHardwareEvent == NULL || hEndHardwareEvent == NULL) return FALSE;
362 if (VDMBuffer
!= NULL
) return FALSE
;
364 VDMBufferSize
= dwVDMBufferSize
;
366 /* HACK: Cache -- to be removed in the real implementation */
367 CharBuff
= RtlAllocateHeap(RtlGetProcessHeap(),
369 VDMBufferSize
.X
* VDMBufferSize
.Y
370 * sizeof(*CharBuff
));
373 VDMBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
375 VDMBufferSize
.X
* VDMBufferSize
.Y
376 * sizeof(*VDMBuffer
));
377 *lpVDMBuffer
= VDMBuffer
;
378 return (VDMBuffer
!= NULL
);
382 /* HACK: Cache -- to be removed in the real implementation */
383 if (CharBuff
) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff
);
386 if (VDMBuffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, VDMBuffer
);
389 VDMBufferSize
.X
= VDMBufferSize
.Y
= 0;
396 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput
,
397 IN PSMALL_RECT lpRect
)
399 if ((hConsoleOutput
== TextConsoleBuffer
) && (VDMBuffer
!= NULL
))
401 /* HACK: Write the cached data to the console */
403 COORD Origin
= { lpRect
->Left
, lpRect
->Top
};
408 for (i
= 0; i
< VDMBufferSize
.Y
; i
++)
410 for (j
= 0; j
< VDMBufferSize
.X
; j
++)
412 CharBuff
[i
* VDMBufferSize
.X
+ j
].Char
.AsciiChar
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Char
;
413 CharBuff
[i
* VDMBufferSize
.X
+ j
].Attributes
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Attributes
;
417 WriteConsoleOutputA(hConsoleOutput
,
424 return InvalidateConsoleDIBits(hConsoleOutput
, lpRect
);
429 /* PRIVATE FUNCTIONS **********************************************************/
431 static inline DWORD
VgaGetAddressSize(VOID
);
432 static VOID
VgaUpdateTextCursor(VOID
);
434 static inline DWORD
VgaGetVideoBaseAddress(VOID
)
436 return MemoryBase
[(VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03];
439 static VOID
VgaUpdateCursorPosition(VOID
)
442 * Update the cursor position in the VGA registers.
444 WORD Offset
= ConsoleInfo
.dwCursorPosition
.Y
* TextResolution
.X
+
445 ConsoleInfo
.dwCursorPosition
.X
;
447 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
] = LOBYTE(Offset
);
448 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
] = HIBYTE(Offset
);
450 VgaUpdateTextCursor();
453 static BOOL
VgaAttachToConsoleInternal(PCOORD Resolution
)
457 PVIDEO_HARDWARE_STATE_HEADER State
;
459 #ifdef USE_REAL_REGISTERCONSOLEVDM
460 PCHAR_INFO CharBuff
= NULL
;
463 DWORD AddressSize
, ScanlineSize
;
467 COORD Origin
= { 0, 0 };
469 ASSERT(TextFramebuffer
== NULL
);
471 TextResolution
= *Resolution
;
474 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
475 * in the two following APIs:
476 * SrvRegisterConsoleVDM (corresponding Win32 API: RegisterConsoleVDM)
477 * SrvVDMConsoleOperation (corresponding Win32 API: ??)
478 * to check whether the current process is a VDM process, and fails otherwise
479 * with the error 0xC0000022 (STATUS_ACCESS_DENIED).
481 * It is worth it to notice that also basesrv.dll does the same only for the
482 * BaseSrvIsFirstVDM API...
485 /* Register with the console server */
487 __RegisterConsoleVDM(1,
490 AnotherEvent
, // NULL,
492 &Length
, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
493 (PVOID
*)&State
, // NULL,
497 (PVOID
*)&TextFramebuffer
);
500 DisplayMessage(L
"RegisterConsoleVDM failed with error %d\n", GetLastError());
505 #ifdef USE_REAL_REGISTERCONSOLEVDM
506 CharBuff
= RtlAllocateHeap(RtlGetProcessHeap(),
508 TextResolution
.X
* TextResolution
.Y
509 * sizeof(*CharBuff
));
513 /* Retrieve the latest console information */
514 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
516 /* Resize the console */
518 ConRect
.Right
= ConRect
.Left
+ Resolution
->X
- 1;
519 ConRect
.Bottom
= max(ConsoleInfo
.dwCursorPosition
.Y
, Resolution
->Y
- 1);
520 ConRect
.Top
= ConRect
.Bottom
- Resolution
->Y
+ 1;
522 * Use this trick to effectively resize the console buffer and window,
524 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
525 * is smaller than the current console window size, and:
526 * - SetConsoleWindowInfo fails if the new console window size is larger
527 * than the current console screen buffer size.
529 Success
= SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
530 DPRINT1("(attach) SetConsoleScreenBufferSize(1) %s with error %d\n", Success
? "succeeded" : "failed", GetLastError());
531 Success
= SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
532 DPRINT1("(attach) SetConsoleWindowInfo %s with error %d\n", Success
? "succeeded" : "failed", GetLastError());
533 Success
= SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
534 DPRINT1("(attach) SetConsoleScreenBufferSize(2) %s with error %d\n", Success
? "succeeded" : "failed", GetLastError());
536 /* Update the saved console information */
537 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
540 * Copy console data into VGA memory
543 /* Read the data from the console into the framebuffer... */
544 ConRect
.Left
= ConRect
.Top
= 0;
545 ConRect
.Right
= TextResolution
.X
;
546 ConRect
.Bottom
= TextResolution
.Y
;
548 ReadConsoleOutputA(TextConsoleBuffer
,
554 /* ... and copy the framebuffer into the VGA memory */
555 AddressSize
= VgaGetAddressSize();
556 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
558 /* Loop through the scanlines */
559 for (i
= 0; i
< TextResolution
.Y
; i
++)
561 /* Loop through the characters */
562 for (j
= 0; j
< TextResolution
.X
; j
++)
564 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
566 /* Store the character in plane 0 */
567 VgaMemory
[CurrentAddr
] = CharBuff
[i
* TextResolution
.X
+ j
].Char
.AsciiChar
;
569 /* Store the attribute in plane 1 */
570 VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
] = (BYTE
)CharBuff
[i
* TextResolution
.X
+ j
].Attributes
;
573 /* Move to the next scanline */
574 Address
+= ScanlineSize
;
577 #ifdef USE_REAL_REGISTERCONSOLEVDM
578 if (CharBuff
) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff
);
581 VgaUpdateCursorPosition();
586 static VOID
VgaDetachFromConsoleInternal(VOID
)
590 COORD dummySize
= {0};
592 /* Deregister with the console server */
593 __RegisterConsoleVDM(0,
605 TextFramebuffer
= NULL
;
608 static BOOL
IsConsoleHandle(HANDLE hHandle
)
612 /* Check whether the handle may be that of a console... */
613 if ((GetFileType(hHandle
) & ~FILE_TYPE_REMOTE
) != FILE_TYPE_CHAR
)
617 * It may be. Perform another test... The idea comes from the
618 * MSDN description of the WriteConsole API:
620 * "WriteConsole fails if it is used with a standard handle
621 * that is redirected to a file. If an application processes
622 * multilingual output that can be redirected, determine whether
623 * the output handle is a console handle (one method is to call
624 * the GetConsoleMode function and check whether it succeeds).
625 * If the handle is a console handle, call WriteConsole. If the
626 * handle is not a console handle, the output is redirected and
627 * you should call WriteFile to perform the I/O."
629 return GetConsoleMode(hHandle
, &dwMode
);
632 static inline DWORD
VgaGetAddressSize(VOID
)
634 if (VgaCrtcRegisters
[VGA_CRTC_UNDERLINE_REG
] & VGA_CRTC_UNDERLINE_DWORD
)
636 /* Double-word addressing */
637 return 4; // sizeof(DWORD)
639 else if (VgaCrtcRegisters
[VGA_CRTC_MODE_CONTROL_REG
] & VGA_CRTC_MODE_CONTROL_BYTE
)
641 /* Byte addressing */
642 return 1; // sizeof(BYTE)
646 /* Word addressing */
647 return 2; // sizeof(WORD)
651 static inline DWORD
VgaTranslateReadAddress(DWORD Address
)
653 DWORD Offset
= LOWORD(Address
- VgaGetVideoBaseAddress());
656 /* Check for chain-4 and odd-even mode */
657 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
659 /* The lowest two bits are the plane number */
660 Plane
= Offset
& 0x03;
663 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
665 /* The LSB is the plane number */
666 Plane
= Offset
& 0x01;
671 /* Use the read mode */
672 Plane
= VgaGcRegisters
[VGA_GC_READ_MAP_SEL_REG
] & 0x03;
675 /* Return the offset on plane 0 for read mode 1 */
676 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_READ
) return Offset
;
677 else return Offset
+ Plane
* VGA_BANK_SIZE
;
680 static inline DWORD
VgaTranslateWriteAddress(DWORD Address
)
682 DWORD Offset
= LOWORD(Address
- VgaGetVideoBaseAddress());
684 /* Check for chain-4 and odd-even mode */
685 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
687 /* Clear the lowest two bits since they're used to select the bank */
690 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
692 /* Clear the lowest bit since it's used to select odd/even */
696 /* Return the offset on plane 0 */
700 static inline BYTE
VgaTranslateByteForWriting(BYTE Data
, BYTE Plane
)
702 BYTE WriteMode
= VgaGcRegisters
[VGA_GC_MODE_REG
] & 0x03;
703 BYTE BitMask
= VgaGcRegisters
[VGA_GC_BITMASK_REG
];
707 /* In write mode 1 just return the latch register */
708 return VgaLatchRegisters
[Plane
];
713 /* Write modes 0 and 3 rotate the data to the right first */
714 BYTE RotateCount
= VgaGcRegisters
[VGA_GC_ROTATE_REG
] & 0x07;
715 Data
= LOBYTE(((DWORD
)Data
>> RotateCount
) | ((DWORD
)Data
<< (8 - RotateCount
)));
719 /* Write mode 2 expands the appropriate bit to all 8 bits */
720 Data
= (Data
& (1 << Plane
)) ? 0xFF : 0x00;
726 * In write mode 0, the enable set/reset register decides if the
727 * set/reset bit should be expanded to all 8 bits.
729 if (VgaGcRegisters
[VGA_GC_ENABLE_RESET_REG
] & (1 << Plane
))
731 /* Copy the bit from the set/reset register to all 8 bits */
732 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
738 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
739 BYTE LogicalOperation
= (VgaGcRegisters
[VGA_GC_ROTATE_REG
] >> 3) & 0x03;
741 if (LogicalOperation
== 1) Data
&= VgaLatchRegisters
[Plane
];
742 else if (LogicalOperation
== 2) Data
|= VgaLatchRegisters
[Plane
];
743 else if (LogicalOperation
== 3) Data
^= VgaLatchRegisters
[Plane
];
747 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
750 /* Then we expand the bit in the set/reset field */
751 Data
= (VgaGcRegisters
[VGA_GC_RESET_REG
] & (1 << Plane
)) ? 0xFF : 0x00;
754 /* Bits cleared in the bitmask are replaced with latch register bits */
755 Data
= (Data
& BitMask
) | (VgaLatchRegisters
[Plane
] & (~BitMask
));
757 /* Return the byte */
761 static inline VOID
VgaMarkForUpdate(SHORT Row
, SHORT Column
)
763 /* Check if this is the first time the rectangle is updated */
766 UpdateRectangle
.Left
= UpdateRectangle
.Top
= MAXSHORT
;
767 UpdateRectangle
.Right
= UpdateRectangle
.Bottom
= MINSHORT
;
770 /* Expand the rectangle to include the point */
771 UpdateRectangle
.Left
= min(UpdateRectangle
.Left
, Column
);
772 UpdateRectangle
.Right
= max(UpdateRectangle
.Right
, Column
);
773 UpdateRectangle
.Top
= min(UpdateRectangle
.Top
, Row
);
774 UpdateRectangle
.Bottom
= max(UpdateRectangle
.Bottom
, Row
);
776 /* Set the update request flag */
780 static inline ULONG
VgaGetClockFrequency(VOID
)
782 BYTE Numerator
, Denominator
;
784 if (VgaSeqRegisters
[SVGA_SEQ_MCLK_REG
] & SVGA_SEQ_MCLK_VCLK
)
786 /* The VCLK is being generated using the MCLK */
787 ULONG Clock
= (VGA_CLOCK_BASE
* (VgaSeqRegisters
[SVGA_SEQ_MCLK_REG
] & 0x3F)) >> 3;
789 if (VgaSeqRegisters
[SVGA_SEQ_VCLK3_DENOMINATOR_REG
] & 1)
791 /* Use only half of the MCLK as the VCLK */
798 switch ((VgaMiscRegister
>> 2) & 3)
802 Numerator
= VgaSeqRegisters
[SVGA_SEQ_VCLK0_NUMERATOR_REG
];
803 Denominator
= VgaSeqRegisters
[SVGA_SEQ_VCLK0_DENOMINATOR_REG
];
809 Numerator
= VgaSeqRegisters
[SVGA_SEQ_VCLK1_NUMERATOR_REG
];
810 Denominator
= VgaSeqRegisters
[SVGA_SEQ_VCLK1_DENOMINATOR_REG
];
816 Numerator
= VgaSeqRegisters
[SVGA_SEQ_VCLK2_NUMERATOR_REG
];
817 Denominator
= VgaSeqRegisters
[SVGA_SEQ_VCLK2_DENOMINATOR_REG
];
823 Numerator
= VgaSeqRegisters
[SVGA_SEQ_VCLK3_NUMERATOR_REG
];
824 Denominator
= VgaSeqRegisters
[SVGA_SEQ_VCLK3_DENOMINATOR_REG
];
829 /* The numerator is 7-bit */
830 Numerator
&= ~(1 << 7);
832 /* If bit 7 is clear, the denominator is 5-bit */
833 if (!(Denominator
& (1 << 7))) Denominator
&= ~(1 << 6);
835 /* Bit 0 of the denominator is the post-scalar bit */
836 if (Denominator
& 1) Denominator
&= ~1;
837 else Denominator
>>= 1;
839 /* Return the clock frequency in Hz */
840 return (VGA_CLOCK_BASE
* Numerator
) / Denominator
;
843 static VOID
VgaResetSequencer(VOID
)
845 /* Lock extended SVGA registers */
846 VgaSeqRegisters
[SVGA_SEQ_UNLOCK_REG
] = SVGA_SEQ_LOCKED
;
848 /* Initialize the VCLKs */
849 VgaSeqRegisters
[SVGA_SEQ_VCLK0_NUMERATOR_REG
] = 0x66;
850 VgaSeqRegisters
[SVGA_SEQ_VCLK0_DENOMINATOR_REG
] = 0x3B;
851 VgaSeqRegisters
[SVGA_SEQ_VCLK1_NUMERATOR_REG
] = 0x5B;
852 VgaSeqRegisters
[SVGA_SEQ_VCLK1_DENOMINATOR_REG
] = 0x2F;
853 VgaSeqRegisters
[SVGA_SEQ_VCLK2_NUMERATOR_REG
] = 0x45;
854 VgaSeqRegisters
[SVGA_SEQ_VCLK2_DENOMINATOR_REG
] = 0x30;
855 VgaSeqRegisters
[SVGA_SEQ_VCLK3_NUMERATOR_REG
] = 0x7E;
856 VgaSeqRegisters
[SVGA_SEQ_VCLK3_DENOMINATOR_REG
] = 0x33;
858 /* 50 MHz MCLK, not being used as the VCLK */
859 VgaSeqRegisters
[SVGA_SEQ_MCLK_REG
] = 0x1C;
862 static VOID
VgaRestoreDefaultPalette(PPALETTEENTRY Entries
, USHORT NumOfEntries
)
866 /* Copy the colors of the default palette to the DAC and console palette */
867 for (i
= 0; i
< NumOfEntries
; i
++)
869 /* Set the palette entries */
870 Entries
[i
].peRed
= GetRValue(VgaDefaultPalette
[i
]);
871 Entries
[i
].peGreen
= GetGValue(VgaDefaultPalette
[i
]);
872 Entries
[i
].peBlue
= GetBValue(VgaDefaultPalette
[i
]);
873 Entries
[i
].peFlags
= 0;
875 /* Set the DAC registers */
876 VgaDacRegisters
[i
* 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette
[i
]));
877 VgaDacRegisters
[i
* 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette
[i
]));
878 VgaDacRegisters
[i
* 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette
[i
]));
882 static BOOLEAN
VgaInitializePalette(VOID
)
885 BOOLEAN Result
= FALSE
;
886 LPLOGPALETTE Palette
, TextPalette
;
888 /* Allocate storage space for the palettes */
889 Palette
= RtlAllocateHeap(RtlGetProcessHeap(),
892 VGA_MAX_COLORS
* sizeof(PALETTEENTRY
));
893 TextPalette
= RtlAllocateHeap(RtlGetProcessHeap(),
896 (VGA_AC_PAL_F_REG
+ 1) * sizeof(PALETTEENTRY
));
897 if ((Palette
== NULL
) || (TextPalette
== NULL
)) goto Cleanup
;
899 /* Initialize the palettes */
900 Palette
->palVersion
= TextPalette
->palVersion
= 0x0300;
901 Palette
->palNumEntries
= VGA_MAX_COLORS
;
902 TextPalette
->palNumEntries
= VGA_AC_PAL_F_REG
+ 1;
904 /* Restore the default graphics palette */
905 VgaRestoreDefaultPalette(Palette
->palPalEntry
, Palette
->palNumEntries
);
907 /* Set the default text palette */
908 for (i
= 0; i
< TextPalette
->palNumEntries
; i
++)
910 /* Set the palette entries */
911 TextPalette
->palPalEntry
[i
].peRed
= GetRValue(ConsoleColors
[i
]);
912 TextPalette
->palPalEntry
[i
].peGreen
= GetGValue(ConsoleColors
[i
]);
913 TextPalette
->palPalEntry
[i
].peBlue
= GetBValue(ConsoleColors
[i
]);
914 TextPalette
->palPalEntry
[i
].peFlags
= 0;
917 /* Create the palettes */
918 PaletteHandle
= CreatePalette(Palette
);
919 TextPaletteHandle
= CreatePalette(TextPalette
);
921 if (PaletteHandle
!= NULL
&& TextPaletteHandle
!= NULL
)
923 /* The palettes have been created successfully */
928 /* Free the palettes */
929 if (Palette
) RtlFreeHeap(RtlGetProcessHeap(), 0, Palette
);
930 if (TextPalette
) RtlFreeHeap(RtlGetProcessHeap(), 0, TextPalette
);
934 /* Something failed, delete the palettes */
935 if (PaletteHandle
) DeleteObject(PaletteHandle
);
936 if (TextPaletteHandle
) DeleteObject(TextPaletteHandle
);
942 static VOID
VgaResetPalette(VOID
)
944 PALETTEENTRY Entries
[VGA_MAX_COLORS
];
946 /* Restore the default palette */
947 VgaRestoreDefaultPalette(Entries
, VGA_MAX_COLORS
);
948 SetPaletteEntries(PaletteHandle
, 0, VGA_MAX_COLORS
, Entries
);
949 PaletteChanged
= TRUE
;
952 static VOID
VgaSetActiveScreenBuffer(HANDLE ScreenBuffer
)
954 ASSERT(ScreenBuffer
);
956 /* Set the active buffer and reattach the VDM UI to it */
957 SetConsoleActiveScreenBuffer(ScreenBuffer
);
958 ConsoleReattach(ScreenBuffer
);
961 static BOOL
VgaEnterGraphicsMode(PCOORD Resolution
)
964 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
965 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
966 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
967 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
969 LONG Width
= Resolution
->X
;
970 LONG Height
= Resolution
->Y
;
972 /* Use DoubleVision mode if the resolution is too small */
973 DoubleWidth
= (Width
< VGA_MINIMUM_WIDTH
);
974 if (DoubleWidth
) Width
*= 2;
975 DoubleHeight
= (Height
< VGA_MINIMUM_HEIGHT
);
976 if (DoubleHeight
) Height
*= 2;
978 /* Fill the bitmap info header */
979 RtlZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BitmapInfo
->bmiHeader
));
980 BitmapInfo
->bmiHeader
.biSize
= sizeof(BitmapInfo
->bmiHeader
);
981 BitmapInfo
->bmiHeader
.biWidth
= Width
;
982 BitmapInfo
->bmiHeader
.biHeight
= Height
;
983 BitmapInfo
->bmiHeader
.biBitCount
= 8;
984 BitmapInfo
->bmiHeader
.biPlanes
= 1;
985 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
986 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
988 /* Fill the palette data */
989 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
991 /* Fill the console graphics buffer info */
992 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
993 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
994 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
996 /* Create the buffer */
997 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
998 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1000 CONSOLE_GRAPHICS_BUFFER
,
1001 &GraphicsBufferInfo
);
1002 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
1004 /* Save the framebuffer address and mutex */
1005 GraphicsFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
1006 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
1008 /* Clear the framebuffer */
1009 RtlZeroMemory(GraphicsFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
1011 /* Set the active buffer */
1012 VgaSetActiveScreenBuffer(GraphicsConsoleBuffer
);
1014 /* The active framebuffer is now the graphics framebuffer */
1015 ConsoleFramebuffer
= GraphicsFramebuffer
;
1017 /* Set the graphics mode palette */
1018 SetConsolePalette(GraphicsConsoleBuffer
,
1020 SYSPAL_NOSTATIC256
);
1022 /* Set the screen mode flag */
1023 ScreenMode
= GRAPHICS_MODE
;
1028 static VOID
VgaLeaveGraphicsMode(VOID
)
1030 /* Release the console framebuffer mutex */
1031 ReleaseMutex(ConsoleMutex
);
1033 /* Switch back to the default console text buffer */
1034 // VgaSetActiveScreenBuffer(TextConsoleBuffer);
1036 /* Cleanup the video data */
1037 CloseHandle(ConsoleMutex
);
1038 ConsoleMutex
= NULL
;
1039 GraphicsFramebuffer
= NULL
;
1040 CloseHandle(GraphicsConsoleBuffer
);
1041 GraphicsConsoleBuffer
= NULL
;
1043 /* Reset the active framebuffer */
1044 ConsoleFramebuffer
= NULL
;
1046 DoubleWidth
= FALSE
;
1047 DoubleHeight
= FALSE
;
1050 static BOOL
VgaEnterTextMode(PCOORD Resolution
)
1052 /* Switch to the text buffer */
1053 // FIXME: Wouldn't it be preferrable to switch to it AFTER we reset everything??
1054 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
1056 /* Adjust the text framebuffer if we changed the resolution */
1057 if (TextResolution
.X
!= Resolution
->X
||
1058 TextResolution
.Y
!= Resolution
->Y
)
1060 VgaDetachFromConsoleInternal();
1063 * VgaAttachToConsoleInternal sets TextResolution
1064 * to the new resolution and updates ConsoleInfo.
1066 if (!VgaAttachToConsoleInternal(Resolution
))
1068 DisplayMessage(L
"An unexpected error occurred!\n");
1069 EmulatorTerminate();
1075 VgaUpdateCursorPosition();
1078 /* The active framebuffer is now the text framebuffer */
1079 ConsoleFramebuffer
= TextFramebuffer
;
1082 * Set the text mode palette.
1084 * INFORMATION: This call should fail on Windows (and therefore
1085 * we get the default palette and our external behaviour is
1086 * just like Windows' one), but it should success on ReactOS
1087 * (so that we get console palette changes even for text-mode
1088 * screen-buffers, which is a new feature on ReactOS).
1090 SetConsolePalette(TextConsoleBuffer
,
1092 SYSPAL_NOSTATIC256
);
1094 /* Set the screen mode flag */
1095 ScreenMode
= TEXT_MODE
;
1100 static VOID
VgaLeaveTextMode(VOID
)
1102 /* Reset the active framebuffer */
1103 ConsoleFramebuffer
= NULL
;
1106 static VOID
VgaChangeMode(VOID
)
1108 COORD NewResolution
= VgaGetDisplayResolution();
1109 SCREEN_MODE NewScreenMode
=
1110 !(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
) ? TEXT_MODE
1114 * Do not switch to a different screen mode + resolution if the new settings
1115 * are the same as the old ones. Just repaint the full screen.
1117 if ((ScreenMode
== NewScreenMode
) && // CurrResolution == NewResolution
1118 (CurrResolution
.X
== NewResolution
.X
&& CurrResolution
.Y
== NewResolution
.Y
))
1123 // FIXME: Wouldn't it be preferrable to switch to the new console SB
1124 // *ONLY* if we succeeded in setting the new mode??
1126 /* Leave the current video mode */
1127 if (ScreenMode
== GRAPHICS_MODE
)
1128 VgaLeaveGraphicsMode();
1132 /* Update the current resolution */
1133 CurrResolution
= NewResolution
;
1135 /* The new screen mode will be updated via the VgaEnterText/GraphicsMode functions */
1137 /* Check if the new mode is alphanumeric */
1138 if (NewScreenMode
== TEXT_MODE
)
1140 /* Enter new text mode */
1141 if (!VgaEnterTextMode(&CurrResolution
))
1143 DisplayMessage(L
"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
1144 EmulatorTerminate();
1150 /* Enter graphics mode */
1151 if (!VgaEnterGraphicsMode(&CurrResolution
))
1153 DisplayMessage(L
"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
1154 EmulatorTerminate();
1161 /* Trigger a full update of the screen */
1163 UpdateRectangle
.Left
= 0;
1164 UpdateRectangle
.Top
= 0;
1165 UpdateRectangle
.Right
= CurrResolution
.X
;
1166 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
1168 /* Reset the mode change flag */
1169 ModeChanged
= FALSE
;
1172 static VOID
VgaUpdateFramebuffer(VOID
)
1175 DWORD AddressSize
= VgaGetAddressSize();
1176 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1177 BYTE PresetRowScan
= VgaCrtcRegisters
[VGA_CRTC_PRESET_ROW_SCAN_REG
] & 0x1F;
1178 DWORD Address
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_START_ADDR_LOW_REG
],
1179 VgaCrtcRegisters
[VGA_CRTC_START_ADDR_HIGH_REG
])
1180 + PresetRowScan
* ScanlineSize
1181 + ((VgaCrtcRegisters
[VGA_CRTC_PRESET_ROW_SCAN_REG
] >> 5) & 3);
1184 * If the console framebuffer is NULL, that means something
1185 * went wrong earlier and this is the final display refresh.
1187 if (ConsoleFramebuffer
== NULL
) return;
1189 /* Check if we are in text or graphics mode */
1190 if (ScreenMode
== GRAPHICS_MODE
)
1193 PBYTE GraphicsBuffer
= (PBYTE
)ConsoleFramebuffer
;
1194 DWORD InterlaceHighBit
= VGA_INTERLACE_HIGH_BIT
;
1198 * Synchronize access to the graphics framebuffer
1199 * with the console framebuffer mutex.
1201 WaitForSingleObject(ConsoleMutex
, INFINITE
);
1203 /* Shift the high bit right by 1 in odd/even mode */
1204 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
1206 InterlaceHighBit
>>= 1;
1209 /* Loop through the scanlines */
1210 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1212 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1214 /* Odd-numbered line in interlaced mode - set the high bit */
1215 Address
|= InterlaceHighBit
;
1218 /* Loop through the pixels */
1219 for (j
= 0; j
< CurrResolution
.X
; j
++)
1223 /* Apply horizontal pixel panning */
1224 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1226 X
= j
+ ((VgaAcRegisters
[VGA_AC_HORZ_PANNING_REG
] & 0x0F) >> 1);
1230 X
= j
+ (VgaAcRegisters
[VGA_AC_HORZ_PANNING_REG
] & 0x0F);
1233 /* Check the shifting mode */
1234 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFT256
)
1236 /* 4 bits shifted from each plane */
1238 /* Check if this is 16 or 256 color mode */
1239 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1241 /* One byte per pixel */
1242 PixelData
= VgaMemory
[(X
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1243 + LOWORD((Address
+ (X
/ VGA_NUM_BANKS
))
1248 /* 4-bits per pixel */
1250 PixelData
= VgaMemory
[(X
% VGA_NUM_BANKS
) * VGA_BANK_SIZE
1251 + LOWORD((Address
+ (X
/ (VGA_NUM_BANKS
* 2)))
1254 /* Check if we should use the highest 4 bits or lowest 4 */
1255 if (((X
/ VGA_NUM_BANKS
) % 2) == 0)
1267 else if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_SHIFTREG
)
1269 /* Check if this is 16 or 256 color mode */
1270 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1272 // TODO: NOT IMPLEMENTED
1273 DPRINT1("8-bit interleaved mode is not implemented!\n");
1278 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1279 * then 2 bits shifted from plane 1 and 3 for the next 4
1281 DWORD BankNumber
= (X
/ 4) % 2;
1282 DWORD Offset
= Address
+ (X
/ 8);
1283 BYTE LowPlaneData
= VgaMemory
[BankNumber
* VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
1284 BYTE HighPlaneData
= VgaMemory
[(BankNumber
+ 2) * VGA_BANK_SIZE
+ LOWORD(Offset
* AddressSize
)];
1286 /* Extract the two bits from each plane */
1287 LowPlaneData
= (LowPlaneData
>> (6 - ((X
% 4) * 2))) & 0x03;
1288 HighPlaneData
= (HighPlaneData
>> (6 - ((X
% 4) * 2))) & 0x03;
1290 /* Combine them into the pixel */
1291 PixelData
= LowPlaneData
| (HighPlaneData
<< 2);
1296 /* 1 bit shifted from each plane */
1298 /* Check if this is 16 or 256 color mode */
1299 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
)
1301 /* 8 bits per pixel, 2 on each plane */
1303 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1305 /* The data is on plane k, 4 pixels per byte */
1306 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1307 + LOWORD((Address
+ (X
/ VGA_NUM_BANKS
))
1310 /* The mask of the first bit in the pair */
1311 BYTE BitMask
= 1 << (((3 - (X
% VGA_NUM_BANKS
)) * 2) + 1);
1313 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1314 if (PlaneData
& BitMask
) PixelData
|= 1 << k
;
1316 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1317 if (PlaneData
& (BitMask
>> 1)) PixelData
|= 1 << (k
+ 4);
1322 /* 4 bits per pixel, 1 on each plane */
1324 for (k
= 0; k
< VGA_NUM_BANKS
; k
++)
1326 BYTE PlaneData
= VgaMemory
[k
* VGA_BANK_SIZE
1327 + LOWORD((Address
+ (X
/ (VGA_NUM_BANKS
* 2)))
1330 /* If the bit on that plane is set, set it */
1331 if (PlaneData
& (1 << (7 - (X
% 8)))) PixelData
|= 1 << k
;
1336 if (!(VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
))
1339 * In 16 color mode, the value is an index to the AC registers
1340 * if external palette access is disabled, otherwise (in case
1341 * of palette loading) it is a blank pixel.
1343 PixelData
= (VgaAcPalDisable
? VgaAcRegisters
[PixelData
& 0x0F]
1347 /* Take into account DoubleVision mode when checking for pixel updates */
1348 if (DoubleWidth
&& DoubleHeight
)
1350 /* Now check if the resulting pixel data has changed */
1351 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
1353 /* Yes, write the new value */
1354 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1355 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1356 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1357 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1359 /* Mark the specified pixel as changed */
1360 VgaMarkForUpdate(i
, j
);
1363 else if (DoubleWidth
&& !DoubleHeight
)
1365 /* Now check if the resulting pixel data has changed */
1366 if (GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] != PixelData
)
1368 /* Yes, write the new value */
1369 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2)] = PixelData
;
1370 GraphicsBuffer
[(i
* CurrResolution
.X
* 2) + (j
* 2 + 1)] = PixelData
;
1372 /* Mark the specified pixel as changed */
1373 VgaMarkForUpdate(i
, j
);
1376 else if (!DoubleWidth
&& DoubleHeight
)
1378 /* Now check if the resulting pixel data has changed */
1379 if (GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] != PixelData
)
1381 /* Yes, write the new value */
1382 GraphicsBuffer
[(i
* 2 * CurrResolution
.X
) + j
] = PixelData
;
1383 GraphicsBuffer
[((i
* 2 + 1) * CurrResolution
.X
) + j
] = PixelData
;
1385 /* Mark the specified pixel as changed */
1386 VgaMarkForUpdate(i
, j
);
1389 else // if (!DoubleWidth && !DoubleHeight)
1391 /* Now check if the resulting pixel data has changed */
1392 if (GraphicsBuffer
[i
* CurrResolution
.X
+ j
] != PixelData
)
1394 /* Yes, write the new value */
1395 GraphicsBuffer
[i
* CurrResolution
.X
+ j
] = PixelData
;
1397 /* Mark the specified pixel as changed */
1398 VgaMarkForUpdate(i
, j
);
1403 if ((VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) && (i
& 1))
1405 /* Clear the high bit */
1406 Address
&= ~InterlaceHighBit
;
1409 if (!(VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_OE
) || (i
& 1))
1411 /* Move to the next scanline */
1412 Address
+= ScanlineSize
;
1417 * Release the console framebuffer mutex
1418 * so that we allow for repainting.
1420 ReleaseMutex(ConsoleMutex
);
1426 PCHAR_CELL CharBuffer
= (PCHAR_CELL
)ConsoleFramebuffer
;
1430 * Technically, the horizontal panning and preset row count should
1431 * affect text mode too. However, it works on pixels and not characters,
1432 * so we can't support it currently.
1435 /* Loop through the scanlines */
1436 for (i
= 0; i
< CurrResolution
.Y
; i
++)
1438 /* Loop through the characters */
1439 for (j
= 0; j
< CurrResolution
.X
; j
++)
1441 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
1443 /* Plane 0 holds the character itself */
1444 CharInfo
.Char
= VgaMemory
[CurrentAddr
];
1446 /* Plane 1 holds the attribute */
1447 CharInfo
.Attributes
= VgaMemory
[CurrentAddr
+ VGA_BANK_SIZE
];
1449 /* Now check if the resulting character data has changed */
1450 if ((CharBuffer
[i
* CurrResolution
.X
+ j
].Char
!= CharInfo
.Char
) ||
1451 (CharBuffer
[i
* CurrResolution
.X
+ j
].Attributes
!= CharInfo
.Attributes
))
1453 /* Yes, write the new value */
1454 CharBuffer
[i
* CurrResolution
.X
+ j
] = CharInfo
;
1456 /* Mark the specified cell as changed */
1457 VgaMarkForUpdate(i
, j
);
1461 /* Move to the next scanline */
1462 Address
+= ScanlineSize
;
1467 static VOID
VgaUpdateTextCursor(VOID
)
1470 CONSOLE_CURSOR_INFO CursorInfo
;
1472 BOOL CursorVisible
= !(VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x20);
1473 BYTE CursorStart
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_START_REG
] & 0x1F;
1474 BYTE CursorEnd
= VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] & 0x1F;
1476 DWORD ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
1477 BYTE TextSize
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
1478 WORD Location
= MAKEWORD(VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
],
1479 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
]);
1481 /* Just return if we are not in text mode */
1482 if (ScreenMode
!= TEXT_MODE
) return;
1484 if (CursorStart
< CursorEnd
)
1486 /* Visible cursor */
1487 CursorInfo
.bVisible
= CursorVisible
;
1488 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
1493 CursorInfo
.bVisible
= FALSE
;
1494 CursorInfo
.dwSize
= 1; // The size needs to be non-zero for SetConsoleCursorInfo to succeed.
1497 /* Add the cursor skew to the location */
1498 Location
+= (VgaCrtcRegisters
[VGA_CRTC_CURSOR_END_REG
] >> 5) & 0x03;
1500 /* Find the coordinates of the new position */
1501 Position
.X
= (SHORT
)(Location
% ScanlineSize
);
1502 Position
.Y
= (SHORT
)(Location
/ ScanlineSize
);
1504 DPRINT("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position
.X
, Position
.Y
);
1506 /* Update the physical cursor */
1507 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
1508 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
1510 /* Reset the cursor changed flag */
1511 CursorChanged
= FALSE
;
1514 static BYTE WINAPI
VgaReadPort(USHORT Port
)
1516 DPRINT("VgaReadPort: Port 0x%X\n", Port
);
1518 if (Port
!= VGA_DAC_MASK
) SvgaHdrCounter
= 0;
1523 return VgaMiscRegister
;
1525 case VGA_INSTAT0_READ
:
1526 return 0; // Not implemented
1528 case VGA_INSTAT1_READ_MONO
:
1529 case VGA_INSTAT1_READ_COLOR
:
1532 BOOLEAN Vsync
, Hsync
;
1533 ULONGLONG Cycles
= GetCycleCount();
1534 ULONG CyclesPerMicrosecond
= (ULONG
)((GetCycleSpeed() + 500000ULL) / 1000000ULL);
1535 ULONG Dots
= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & 1) ? 9 : 8;
1536 ULONG Clock
= VgaGetClockFrequency() / 1000000;
1537 ULONG HorizTotalDots
= ((ULONG
)VgaCrtcRegisters
[VGA_CRTC_HORZ_TOTAL_REG
] + 5) * Dots
;
1538 ULONG VblankStart
, VblankEnd
, HblankStart
, HblankEnd
;
1539 ULONG HblankDuration
, VblankDuration
;
1541 /* Calculate the vertical blanking duration in cycles */
1542 VblankStart
= VgaCrtcRegisters
[VGA_CRTC_START_VERT_BLANKING_REG
] & 0x7F;
1543 VblankEnd
= VgaCrtcRegisters
[VGA_CRTC_END_VERT_BLANKING_REG
] & 0x7F;
1544 if (VblankEnd
< VblankStart
) VblankEnd
|= 0x80;
1545 VblankDuration
= ((VblankEnd
- VblankStart
) * HorizTotalDots
1546 * CyclesPerMicrosecond
+ (Clock
>> 1)) / Clock
;
1548 /* Calculate the horizontal blanking duration in cycles */
1549 HblankStart
= VgaCrtcRegisters
[VGA_CRTC_START_HORZ_BLANKING_REG
] & 0x1F;
1550 HblankEnd
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_BLANKING_REG
] & 0x1F;
1551 if (HblankEnd
< HblankStart
) HblankEnd
|= 0x20;
1552 HblankDuration
= ((HblankEnd
- HblankStart
) * Dots
1553 * CyclesPerMicrosecond
+ (Clock
>> 1)) / Clock
;
1555 Vsync
= (Cycles
- VerticalRetraceCycle
) < (ULONGLONG
)VblankDuration
;
1556 Hsync
= (Cycles
- HorizontalRetraceCycle
) < (ULONGLONG
)HblankDuration
;
1558 /* Reset the AC latch */
1561 /* Reverse the polarity, if needed */
1562 if (VgaMiscRegister
& VGA_MISC_VSYNCP
) Vsync
= !Vsync
;
1563 if (VgaMiscRegister
& VGA_MISC_HSYNCP
) Hsync
= !Hsync
;
1565 /* Set a flag if there is a vertical or horizontal retrace */
1566 if (Vsync
|| Hsync
) Result
|= VGA_STAT_DD
;
1568 /* Set an additional flag if there was a vertical retrace */
1569 if (Vsync
) Result
|= VGA_STAT_VRETRACE
;
1574 case VGA_FEATURE_READ
:
1575 return VgaFeatureRegister
;
1581 return VgaAcRegisters
[VgaAcIndex
];
1587 return VgaSeqRegisters
[VgaSeqIndex
];
1591 if (SvgaHdrCounter
== 4)
1594 return SvgaHiddenRegister
;
1603 case VGA_DAC_READ_INDEX
:
1604 /* This returns the read/write state */
1605 return (VgaDacReadWrite
? 0 : 3);
1607 case VGA_DAC_WRITE_INDEX
:
1612 /* Ignore reads in write mode */
1613 if (!VgaDacReadWrite
)
1615 BYTE Data
= VgaDacRegisters
[VgaDacIndex
* 3 + VgaDacLatchCounter
];
1616 VgaDacLatchCounter
++;
1618 if (VgaDacLatchCounter
== 3)
1620 /* Reset the latch counter and increment the palette index */
1621 VgaDacLatchCounter
= 0;
1623 VgaDacIndex
%= VGA_MAX_COLORS
;
1632 case VGA_CRTC_INDEX_MONO
:
1633 case VGA_CRTC_INDEX_COLOR
:
1634 return VgaCrtcIndex
;
1636 case VGA_CRTC_DATA_MONO
:
1637 case VGA_CRTC_DATA_COLOR
:
1638 return VgaCrtcRegisters
[VgaCrtcIndex
];
1644 return VgaGcRegisters
[VgaGcIndex
];
1647 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port
);
1654 static inline VOID
VgaWriteSequencer(BYTE Data
)
1656 /* Save the value */
1657 VgaSeqRegisters
[VgaSeqIndex
& VGA_SEQ_INDEX_MASK
] = Data
;
1659 /* Check the index */
1660 switch (VgaSeqIndex
& VGA_SEQ_INDEX_MASK
)
1662 case SVGA_SEQ_UNLOCK_REG
:
1664 if ((Data
& SVGA_SEQ_UNLOCK_MASK
) == SVGA_SEQ_UNLOCKED
)
1666 /* Unlock SVGA extensions */
1667 VgaSeqRegisters
[SVGA_SEQ_UNLOCK_REG
] = SVGA_SEQ_UNLOCKED
;
1671 /* Lock SVGA extensions */
1672 VgaSeqRegisters
[SVGA_SEQ_UNLOCK_REG
] = SVGA_SEQ_LOCKED
;
1680 static inline VOID
VgaWriteGc(BYTE Data
)
1682 /* Save the value */
1683 VgaGcRegisters
[VgaGcIndex
& VGA_GC_INDEX_MASK
] = Data
;
1685 /* Check the index */
1686 switch (VgaGcIndex
& VGA_GC_INDEX_MASK
)
1688 case VGA_GC_MISC_REG
:
1690 /* Remove any existing VGA memory hook */
1691 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
1693 if (VgaMiscRegister
& VGA_MISC_RAM_ENABLED
)
1695 UCHAR MemoryMap
= (VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03;
1697 /* Register a memory hook */
1698 MemInstallFastMemoryHook((PVOID
)MemoryBase
[MemoryMap
],
1699 MemorySize
[MemoryMap
],
1704 /* The GC misc register decides if it's text or graphics mode */
1711 static inline VOID
VgaWriteCrtc(BYTE Data
)
1713 /* Save the value */
1714 VgaCrtcRegisters
[VgaCrtcIndex
& VGA_CRTC_INDEX_MASK
] = Data
;
1716 /* Check the index */
1717 switch (VgaCrtcIndex
& VGA_CRTC_INDEX_MASK
)
1719 case VGA_CRTC_END_HORZ_DISP_REG
:
1720 case VGA_CRTC_VERT_DISP_END_REG
:
1721 case VGA_CRTC_OVERFLOW_REG
:
1722 case VGA_CRTC_MAX_SCAN_LINE_REG
:
1724 /* The video mode has changed */
1729 case VGA_CRTC_CURSOR_LOC_LOW_REG
:
1730 case VGA_CRTC_CURSOR_LOC_HIGH_REG
:
1731 case VGA_CRTC_CURSOR_START_REG
:
1732 case VGA_CRTC_CURSOR_END_REG
:
1734 /* Set the cursor changed flag */
1735 CursorChanged
= TRUE
;
1741 static inline VOID
VgaWriteDac(BYTE Data
)
1746 /* Store the value in the latch */
1747 VgaDacLatch
[VgaDacLatchCounter
++] = Data
;
1748 if (VgaDacLatchCounter
< 3) return;
1750 /* Reset the latch counter */
1751 VgaDacLatchCounter
= 0;
1753 /* Set the DAC register values */
1754 VgaDacRegisters
[VgaDacIndex
* 3] = VgaDacLatch
[0];
1755 VgaDacRegisters
[VgaDacIndex
* 3 + 1] = VgaDacLatch
[1];
1756 VgaDacRegisters
[VgaDacIndex
* 3 + 2] = VgaDacLatch
[2];
1758 /* Fill the entry structure */
1759 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacLatch
[0]);
1760 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacLatch
[1]);
1761 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacLatch
[2]);
1764 /* Update the palette entry */
1765 SetPaletteEntries(PaletteHandle
, VgaDacIndex
, 1, &Entry
);
1767 /* Check which text palette entries are affected */
1768 for (i
= 0; i
<= VGA_AC_PAL_F_REG
; i
++)
1770 if (VgaAcRegisters
[i
] == VgaDacIndex
)
1772 /* Update the text palette entry */
1773 SetPaletteEntries(TextPaletteHandle
, i
, 1, &Entry
);
1777 /* Set the palette changed flag */
1778 PaletteChanged
= TRUE
;
1780 /* Update the index */
1782 VgaDacIndex
%= VGA_MAX_COLORS
;
1785 static inline VOID
VgaWriteAc(BYTE Data
)
1789 ASSERT(VgaAcIndex
< VGA_AC_MAX_REG
);
1791 /* Save the value */
1792 if (VgaAcIndex
<= VGA_AC_PAL_F_REG
)
1794 if (VgaAcPalDisable
) return;
1796 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
1797 if (VgaAcRegisters
[VgaAcIndex
] != Data
)
1799 /* Update the AC register */
1800 VgaAcRegisters
[VgaAcIndex
] = Data
;
1802 /* Fill the entry structure */
1803 Entry
.peRed
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3]);
1804 Entry
.peGreen
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 1]);
1805 Entry
.peBlue
= VGA_DAC_TO_COLOR(VgaDacRegisters
[Data
* 3 + 2]);
1808 /* Update the palette entry and set the palette change flag */
1809 SetPaletteEntries(TextPaletteHandle
, VgaAcIndex
, 1, &Entry
);
1810 PaletteChanged
= TRUE
;
1815 VgaAcRegisters
[VgaAcIndex
] = Data
;
1819 static VOID WINAPI
VgaWritePort(USHORT Port
, BYTE Data
)
1821 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port
, Data
);
1825 case VGA_MISC_WRITE
:
1827 VgaMiscRegister
= Data
;
1829 if (VgaMiscRegister
& 0x01)
1831 /* Color emulation */
1832 DPRINT1("Color emulation\n");
1834 /* Register the new I/O Ports */
1835 RegisterIoPort(0x3D4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_COLOR
1836 RegisterIoPort(0x3D5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_COLOR
1837 RegisterIoPort(0x3DA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1839 /* Unregister the old ones */
1840 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1841 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1842 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1846 /* Monochrome emulation */
1847 DPRINT1("Monochrome emulation\n");
1849 /* Register the new I/O Ports */
1850 RegisterIoPort(0x3B4, VgaReadPort
, VgaWritePort
); // VGA_CRTC_INDEX_MONO
1851 RegisterIoPort(0x3B5, VgaReadPort
, VgaWritePort
); // VGA_CRTC_DATA_MONO
1852 RegisterIoPort(0x3BA, VgaReadPort
, VgaWritePort
); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1854 /* Unregister the old ones */
1855 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1856 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1857 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1860 /* Remove any existing VGA memory hook */
1861 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
1863 if (VgaMiscRegister
& VGA_MISC_RAM_ENABLED
)
1865 UCHAR MemoryMap
= (VgaGcRegisters
[VGA_GC_MISC_REG
] >> 2) & 0x03;
1867 /* Register a memory hook */
1868 MemInstallFastMemoryHook((PVOID
)MemoryBase
[MemoryMap
],
1869 MemorySize
[MemoryMap
],
1877 case VGA_FEATURE_WRITE_MONO
:
1878 case VGA_FEATURE_WRITE_COLOR
:
1880 VgaFeatureRegister
= Data
;
1885 // case VGA_AC_WRITE:
1889 /* Change the index */
1890 BYTE Index
= Data
& 0x1F;
1891 if (Index
< VGA_AC_MAX_REG
) VgaAcIndex
= Index
;
1894 * Change palette protection by checking for
1895 * the Palette Address Source bit.
1897 VgaAcPalDisable
= (Data
& 0x20) ? TRUE
: FALSE
;
1901 /* Write the data */
1905 /* Toggle the latch */
1906 VgaAcLatch
= !VgaAcLatch
;
1912 /* Set the sequencer index register */
1913 if ((Data
& 0x1F) < SVGA_SEQ_MAX_UNLOCKED_REG
1914 && (Data
& 0x1F) != VGA_SEQ_MAX_REG
)
1924 /* Call the sequencer function */
1925 VgaWriteSequencer(Data
);
1931 if (SvgaHdrCounter
== 4) SvgaHiddenRegister
= Data
;
1932 else VgaDacMask
= Data
;
1937 case VGA_DAC_READ_INDEX
:
1939 VgaDacReadWrite
= FALSE
;
1941 VgaDacLatchCounter
= 0;
1945 case VGA_DAC_WRITE_INDEX
:
1947 VgaDacReadWrite
= TRUE
;
1949 VgaDacLatchCounter
= 0;
1955 /* Ignore writes in read mode */
1956 if (VgaDacReadWrite
) VgaWriteDac(Data
& 0x3F);
1960 case VGA_CRTC_INDEX_MONO
:
1961 case VGA_CRTC_INDEX_COLOR
:
1963 /* Set the CRTC index register */
1964 if (((Data
& VGA_CRTC_INDEX_MASK
) < SVGA_CRTC_MAX_UNLOCKED_REG
)
1965 && ((Data
& VGA_CRTC_INDEX_MASK
) < SVGA_CRTC_UNUSED0_REG
1966 || (Data
& VGA_CRTC_INDEX_MASK
) > SVGA_CRTC_UNUSED6_REG
)
1967 && (Data
& VGA_CRTC_INDEX_MASK
) != SVGA_CRTC_UNUSED7_REG
)
1969 VgaCrtcIndex
= Data
;
1975 case VGA_CRTC_DATA_MONO
:
1976 case VGA_CRTC_DATA_COLOR
:
1978 /* Call the CRTC function */
1985 /* Set the GC index register */
1986 if ((Data
& VGA_GC_INDEX_MASK
) < SVGA_GC_MAX_UNLOCKED_REG
1987 && (Data
& VGA_GC_INDEX_MASK
) != SVGA_GC_UNUSED0_REG
1988 && ((Data
& VGA_GC_INDEX_MASK
) < SVGA_GC_UNUSED1_REG
1989 || (Data
& VGA_GC_INDEX_MASK
) > SVGA_GC_UNUSED10_REG
))
1999 /* Call the GC function */
2005 DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port
, Data
);
2012 static VOID FASTCALL
VgaVerticalRetrace(ULONGLONG ElapsedTime
)
2014 HANDLE ConsoleBufferHandle
= NULL
;
2016 UNREFERENCED_PARAMETER(ElapsedTime
);
2018 /* Set the vertical retrace cycle */
2019 VerticalRetraceCycle
= GetCycleCount();
2021 /* If nothing has changed, just return */
2022 // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
2025 /* Change the display mode */
2026 if (ModeChanged
) VgaChangeMode();
2028 /* Change the text cursor appearance */
2029 if (CursorChanged
) VgaUpdateTextCursor();
2033 /* Trigger a full update of the screen */
2035 UpdateRectangle
.Left
= 0;
2036 UpdateRectangle
.Top
= 0;
2037 UpdateRectangle
.Right
= CurrResolution
.X
;
2038 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
2040 PaletteChanged
= FALSE
;
2043 /* Update the contents of the framebuffer */
2044 VgaUpdateFramebuffer();
2046 /* Ignore if there's nothing to update */
2047 if (!NeedsUpdate
) return;
2049 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
2050 UpdateRectangle
.Left
,
2051 UpdateRectangle
.Top
,
2052 UpdateRectangle
.Right
,
2053 UpdateRectangle
.Bottom
);
2055 /* Check if we are in text or graphics mode */
2056 if (ScreenMode
== GRAPHICS_MODE
)
2059 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
2061 /* In DoubleVision mode, scale the update rectangle */
2064 UpdateRectangle
.Left
*= 2;
2065 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
2069 UpdateRectangle
.Top
*= 2;
2070 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
2076 ConsoleBufferHandle
= TextConsoleBuffer
;
2079 /* Redraw the screen */
2080 __InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
2082 /* Clear the update flag */
2083 NeedsUpdate
= FALSE
;
2086 static VOID FASTCALL
VgaHorizontalRetrace(ULONGLONG ElapsedTime
)
2088 UNREFERENCED_PARAMETER(ElapsedTime
);
2091 HorizontalRetraceCycle
= GetCycleCount();
2094 /* PUBLIC FUNCTIONS ***********************************************************/
2096 COORD
VgaGetDisplayResolution(VOID
)
2099 BYTE MaximumScanLine
= 1 + (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & 0x1F);
2101 /* The low 8 bits are in the display registers */
2102 Resolution
.X
= VgaCrtcRegisters
[VGA_CRTC_END_HORZ_DISP_REG
];
2103 Resolution
.Y
= VgaCrtcRegisters
[VGA_CRTC_VERT_DISP_END_REG
];
2105 /* Set the top bits from the overflow register */
2106 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE8
)
2108 Resolution
.Y
|= 1 << 8;
2110 if (VgaCrtcRegisters
[VGA_CRTC_OVERFLOW_REG
] & VGA_CRTC_OVERFLOW_VDE9
)
2112 Resolution
.Y
|= 1 << 9;
2115 /* Increase the values by 1 */
2119 if (VgaGcRegisters
[VGA_GC_MISC_REG
] & VGA_GC_MISC_NOALPHA
)
2121 /* Multiply the horizontal resolution by the 9/8 dot mode */
2122 Resolution
.X
*= (VgaSeqRegisters
[VGA_SEQ_CLOCK_REG
] & VGA_SEQ_CLOCK_98DM
)
2125 /* The horizontal resolution is halved in 8-bit mode */
2126 if (VgaAcRegisters
[VGA_AC_CONTROL_REG
] & VGA_AC_CONTROL_8BIT
) Resolution
.X
/= 2;
2129 if (VgaCrtcRegisters
[VGA_CRTC_MAX_SCAN_LINE_REG
] & VGA_CRTC_MAXSCANLINE_DOUBLE
)
2131 /* Halve the vertical resolution */
2136 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
2137 Resolution
.Y
/= MaximumScanLine
;
2140 /* Return the resolution */
2144 BOOLEAN
VgaGetDoubleVisionState(PBOOLEAN Horizontal
, PBOOLEAN Vertical
)
2146 if (GraphicsConsoleBuffer
== NULL
) return FALSE
;
2147 if (Horizontal
) *Horizontal
= DoubleWidth
;
2148 if (Vertical
) *Vertical
= DoubleHeight
;
2152 VOID
VgaRefreshDisplay(VOID
)
2154 VgaVerticalRetrace(0);
2157 VOID FASTCALL
VgaReadMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
2161 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
2163 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
2165 /* Ignore if video RAM access is disabled */
2166 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return;
2168 if (!(VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_READ
))
2170 /* Loop through each byte */
2171 for (i
= 0; i
< Size
; i
++)
2173 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
2175 /* Copy the value to the buffer */
2176 BufPtr
[i
] = VgaMemory
[VideoAddress
];
2181 /* Loop through each byte */
2182 for (i
= 0; i
< Size
; i
++)
2186 /* This should always return a plane 0 address for read mode 1 */
2187 VideoAddress
= VgaTranslateReadAddress(Address
+ i
);
2189 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
2191 /* Don't consider ignored banks */
2192 if (!(VgaGcRegisters
[VGA_GC_COLOR_IGNORE_REG
] & (1 << j
))) continue;
2194 if (VgaGcRegisters
[VGA_GC_COLOR_COMPARE_REG
] & (1 << j
))
2196 /* Comparing with 11111111 */
2197 Result
&= VgaMemory
[j
* VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
2201 /* Comparing with 00000000 */
2202 Result
&= ~(VgaMemory
[j
* VGA_BANK_SIZE
+ LOWORD(VideoAddress
)]);
2206 /* Copy the value to the buffer */
2211 /* Load the latch registers */
2212 VgaLatchRegisters
[0] = VgaMemory
[LOWORD(VideoAddress
)];
2213 VgaLatchRegisters
[1] = VgaMemory
[VGA_BANK_SIZE
+ LOWORD(VideoAddress
)];
2214 VgaLatchRegisters
[2] = VgaMemory
[(2 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
2215 VgaLatchRegisters
[3] = VgaMemory
[(3 * VGA_BANK_SIZE
) + LOWORD(VideoAddress
)];
2218 BOOLEAN FASTCALL
VgaWriteMemory(ULONG Address
, PVOID Buffer
, ULONG Size
)
2222 PUCHAR BufPtr
= (PUCHAR
)Buffer
;
2224 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address
, Size
);
2226 /* Ignore if video RAM access is disabled */
2227 if ((VgaMiscRegister
& VGA_MISC_RAM_ENABLED
) == 0) return TRUE
;
2229 /* Also ignore if write access to all planes is disabled */
2230 if ((VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & 0x0F) == 0x00) return TRUE
;
2232 /* Loop through each byte */
2233 for (i
= 0; i
< Size
; i
++)
2235 VideoAddress
= VgaTranslateWriteAddress(Address
+ i
);
2237 for (j
= 0; j
< VGA_NUM_BANKS
; j
++)
2239 /* Make sure the page is writeable */
2240 if (!(VgaSeqRegisters
[VGA_SEQ_MASK_REG
] & (1 << j
))) continue;
2242 /* Check if this is chain-4 mode */
2243 if (VgaSeqRegisters
[VGA_SEQ_MEM_REG
] & VGA_SEQ_MEM_C4
)
2245 if (((Address
+ i
) & 0x03) != j
)
2247 /* This plane will not be accessed */
2252 /* Check if this is odd-even mode */
2253 if (VgaGcRegisters
[VGA_GC_MODE_REG
] & VGA_GC_MODE_OE
)
2255 if (((Address
+ i
) & 0x01) != (j
& 1))
2257 /* This plane will not be accessed */
2262 /* Copy the value to the VGA memory */
2263 VgaMemory
[VideoAddress
+ j
* VGA_BANK_SIZE
] = VgaTranslateByteForWriting(BufPtr
[i
], j
);
2270 VOID
VgaClearMemory(VOID
)
2272 RtlZeroMemory(VgaMemory
, sizeof(VgaMemory
));
2275 VOID
VgaWriteTextModeFont(UINT FontNumber
, CONST UCHAR
* FontData
, UINT Height
)
2278 PUCHAR FontMemory
= (PUCHAR
)&VgaMemory
[VGA_BANK_SIZE
* VGA_FONT_BANK
+ (FontNumber
* VGA_FONT_SIZE
)];
2280 ASSERT(Height
<= VGA_MAX_FONT_HEIGHT
);
2282 for (i
= 0 ; i
< VGA_FONT_CHARACTERS
; i
++)
2284 /* Write the character */
2285 for (j
= 0; j
< Height
; j
++)
2287 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = FontData
[i
* Height
+ j
];
2290 /* Clear the unused part */
2291 for (j
= Height
; j
< VGA_MAX_FONT_HEIGHT
; j
++)
2293 FontMemory
[i
* VGA_MAX_FONT_HEIGHT
+ j
] = 0;
2298 VOID
ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent
)
2300 DPRINT1("Screen events not handled\n");
2303 BOOL
VgaAttachToConsole(VOID
)
2305 if (TextResolution
.X
== 0 || TextResolution
.Y
== 0)
2306 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
2308 if (TextResolution
.X
== 0) TextResolution
.X
= 80;
2309 if (TextResolution
.Y
== 0) TextResolution
.Y
= 25;
2311 // VgaDetachFromConsoleInternal();
2314 * VgaAttachToConsoleInternal sets TextResolution
2315 * to the new resolution and updates ConsoleInfo.
2317 if (!VgaAttachToConsoleInternal(&TextResolution
))
2319 DisplayMessage(L
"An unexpected error occurred!\n");
2320 EmulatorTerminate();
2324 /* Restore the original screen buffer */
2325 VgaSetActiveScreenBuffer(ScreenBufferHandle
);
2326 ScreenBufferHandle
= NULL
;
2328 /* Restore the screen state */
2329 if (ScreenMode
== TEXT_MODE
)
2331 /* The text mode framebuffer was recreated */
2332 ConsoleFramebuffer
= TextFramebuffer
;
2336 /* The graphics mode framebuffer is unchanged */
2337 ConsoleFramebuffer
= OldConsoleFramebuffer
;
2339 OldConsoleFramebuffer
= NULL
;
2344 VOID
VgaDetachFromConsole(VOID
)
2350 VgaDetachFromConsoleInternal();
2352 /* Save the screen state */
2353 if (ScreenMode
== TEXT_MODE
)
2354 ScreenBufferHandle
= TextConsoleBuffer
;
2356 ScreenBufferHandle
= GraphicsConsoleBuffer
;
2358 /* Reset the active framebuffer */
2359 OldConsoleFramebuffer
= ConsoleFramebuffer
;
2360 ConsoleFramebuffer
= NULL
;
2362 /* Restore the original console size */
2363 ConRect
.Left
= ConRect
.Top
= 0;
2364 ConRect
.Right
= ConRect
.Left
+ OrgConsoleBufferInfo
.srWindow
.Right
- OrgConsoleBufferInfo
.srWindow
.Left
;
2365 ConRect
.Bottom
= ConRect
.Top
+ OrgConsoleBufferInfo
.srWindow
.Bottom
- OrgConsoleBufferInfo
.srWindow
.Top
;
2366 /* See the following trick explanation in VgaAttachToConsoleInternal */
2367 Success
= SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
2368 DPRINT1("(detach) SetConsoleScreenBufferSize(1) %s with error %d\n", Success
? "succeeded" : "failed", GetLastError());
2369 Success
= SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
2370 DPRINT1("(detach) SetConsoleWindowInfo %s with error %d\n", Success
? "succeeded" : "failed", GetLastError());
2371 Success
= SetConsoleScreenBufferSize(TextConsoleBuffer
, OrgConsoleBufferInfo
.dwSize
);
2372 DPRINT1("(detach) SetConsoleScreenBufferSize(2) %s with error %d\n", Success
? "succeeded" : "failed", GetLastError());
2374 /* Restore the original cursor shape */
2375 SetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
);
2377 // FIXME: Should we copy back the screen data to the screen buffer??
2378 // WriteConsoleOutputA(...);
2380 // FIXME: Should we change cursor POSITION??
2381 // VgaUpdateTextCursor();
2383 ///* Update the physical cursor */
2384 //SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
2385 //SetConsoleCursorPosition(TextConsoleBuffer, Position /*OrgConsoleBufferInfo.dwCursorPosition*/);
2387 /* Restore the old text-mode screen buffer */
2388 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2391 BOOLEAN
VgaInitialize(HANDLE TextHandle
)
2393 /* Save the default text-mode console output handle */
2394 if (!IsConsoleHandle(TextHandle
)) return FALSE
;
2395 TextConsoleBuffer
= TextHandle
;
2397 /* Save the original cursor and console screen buffer information */
2398 if (!GetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
) ||
2399 !GetConsoleScreenBufferInfo(TextConsoleBuffer
, &OrgConsoleBufferInfo
))
2403 ConsoleInfo
= OrgConsoleBufferInfo
;
2405 /* Clear the SEQ, GC, CRTC and AC registers */
2406 RtlZeroMemory(VgaSeqRegisters
, sizeof(VgaSeqRegisters
));
2407 RtlZeroMemory(VgaGcRegisters
, sizeof(VgaGcRegisters
));
2408 RtlZeroMemory(VgaCrtcRegisters
, sizeof(VgaCrtcRegisters
));
2409 RtlZeroMemory(VgaAcRegisters
, sizeof(VgaAcRegisters
));
2411 /* Initialize the VGA palette and fail if it isn't successfully created */
2412 if (!VgaInitializePalette()) return FALSE
;
2413 /***/ VgaResetPalette(); /***/
2415 /* Switch to the text buffer, but do not enter into a text mode */
2416 VgaSetActiveScreenBuffer(TextConsoleBuffer
);
2418 /* Reset the sequencer */
2419 VgaResetSequencer();
2421 /* Clear the VGA memory */
2424 /* Register the I/O Ports */
2425 RegisterIoPort(0x3CC, VgaReadPort
, NULL
); // VGA_MISC_READ
2426 RegisterIoPort(0x3C2, VgaReadPort
, VgaWritePort
); // VGA_MISC_WRITE, VGA_INSTAT0_READ
2427 RegisterIoPort(0x3CA, VgaReadPort
, NULL
); // VGA_FEATURE_READ
2428 RegisterIoPort(0x3C0, VgaReadPort
, VgaWritePort
); // VGA_AC_INDEX, VGA_AC_WRITE
2429 RegisterIoPort(0x3C1, VgaReadPort
, NULL
); // VGA_AC_READ
2430 RegisterIoPort(0x3C4, VgaReadPort
, VgaWritePort
); // VGA_SEQ_INDEX
2431 RegisterIoPort(0x3C5, VgaReadPort
, VgaWritePort
); // VGA_SEQ_DATA
2432 RegisterIoPort(0x3C6, VgaReadPort
, VgaWritePort
); // VGA_DAC_MASK
2433 RegisterIoPort(0x3C7, VgaReadPort
, VgaWritePort
); // VGA_DAC_READ_INDEX
2434 RegisterIoPort(0x3C8, VgaReadPort
, VgaWritePort
); // VGA_DAC_WRITE_INDEX
2435 RegisterIoPort(0x3C9, VgaReadPort
, VgaWritePort
); // VGA_DAC_DATA
2436 RegisterIoPort(0x3CE, VgaReadPort
, VgaWritePort
); // VGA_GC_INDEX
2437 RegisterIoPort(0x3CF, VgaReadPort
, VgaWritePort
); // VGA_GC_DATA
2439 /* CGA ports for compatibility, unimplemented */
2440 RegisterIoPort(0x3D8, VgaReadPort
, VgaWritePort
); // CGA_MODE_CTRL_REG
2441 RegisterIoPort(0x3D9, VgaReadPort
, VgaWritePort
); // CGA_PAL_CTRL_REG
2443 HSyncTimer
= CreateHardwareTimer(HARDWARE_TIMER_ENABLED
, HZ_TO_NS(31469), VgaHorizontalRetrace
);
2444 VSyncTimer
= CreateHardwareTimer(HARDWARE_TIMER_ENABLED
, HZ_TO_NS(60), VgaVerticalRetrace
);
2446 /* Return success */
2450 VOID
VgaCleanup(VOID
)
2452 /* Do a final display refresh */
2453 VgaRefreshDisplay();
2455 DestroyHardwareTimer(VSyncTimer
);
2456 DestroyHardwareTimer(HSyncTimer
);
2458 /* Leave the current video mode */
2459 if (ScreenMode
== GRAPHICS_MODE
)
2460 VgaLeaveGraphicsMode();
2464 VgaDetachFromConsole();
2465 MemRemoveFastMemoryHook((PVOID
)0xA0000, 0x20000);
2467 CloseHandle(AnotherEvent
);
2468 CloseHandle(EndEvent
);
2469 CloseHandle(StartEvent
);