[NTVDM]: Improve the console resize algorithm.
[reactos.git] / reactos / subsystems / mvdm / ntvdm / hardware / video / svga.c
1 /*
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>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "ntvdm.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 #include "emulator.h"
17 #include "svga.h"
18 #include <bios/vidbios.h>
19
20 #include "memory.h"
21 #include "io.h"
22 #include "clock.h"
23
24 /* PRIVATE VARIABLES **********************************************************/
25
26 static CONST DWORD MemoryBase[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
27 static CONST DWORD MemorySize[] = { 0x20000, 0x10000, 0x08000, 0x08000 };
28
29 /*
30 * Activate this line if you want to use the real
31 * RegisterConsoleVDM API of ReactOS/Windows.
32 */
33 // #define USE_REAL_REGISTERCONSOLEVDM
34
35 #define USE_REACTOS_COLORS
36 // #define USE_DOSBOX_COLORS
37
38 #if defined(USE_REACTOS_COLORS)
39
40 // ReactOS colors
41 static CONST COLORREF VgaDefaultPalette[VGA_MAX_COLORS] =
42 {
43 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
44 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
45 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
46 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
47 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
48 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
49 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
50 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
51 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
52 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
53 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
54 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
55 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
56 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
57 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
58 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
59 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
60 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
61 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
62 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
63 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
64 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
65 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
66 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
67 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
68 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
69 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
70 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
71 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
72 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
73 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
74 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
75 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
76 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
77 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
78 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
79 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
80 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
81 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
82 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
83 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
84 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
85 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
86 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
87 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
88 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
89 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
90 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
91 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
92 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
93 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
94 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
95 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
96 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
97 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
98 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
99 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
100 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
101 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
102 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
103 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
104 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
105 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
106 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
107 };
108
109 #elif defined(USE_DOSBOX_COLORS)
110
111 // DOSBox colors
112 static CONST COLORREF VgaDefaultPalette[VGA_MAX_COLORS] =
113 {
114 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
115 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
116 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
117 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
118 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
119 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
120 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
121 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
122 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
123 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
124 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
125 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
126 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
127 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
128 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
129 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
130
131 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
132 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
133 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
134 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
135 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
136 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
137 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
138 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
139 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
140 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
141 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
142 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
143 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
144 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
145 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
146 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
147
148 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
149 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
150 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
151 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
152 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
153 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
154 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
155 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
156 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
157 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
158 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
159 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
160 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
161 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
162 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
163 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
164
165 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
166 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
167 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
168 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
169 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
170 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
171 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
172 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
173 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
174 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
175 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
176 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
177 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
178 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
179 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
180 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
181 };
182
183 #endif
184
185 /*
186 * Default 16-color palette for foreground and background
187 * (corresponding flags in comments).
188 * Taken from subsystems/win32/winsrv/consrv/frontends/gui/conwnd.c
189 */
190 static const COLORREF ConsoleColors[16] =
191 {
192 RGB(0, 0, 0), // (Black)
193 RGB(0, 0, 128), // BLUE
194 RGB(0, 128, 0), // GREEN
195 RGB(0, 128, 128), // BLUE | GREEN
196 RGB(128, 0, 0), // RED
197 RGB(128, 0, 128), // BLUE | RED
198 RGB(128, 128, 0), // GREEN | RED
199 RGB(192, 192, 192), // BLUE | GREEN | RED
200
201 RGB(128, 128, 128), // (Grey) INTENSITY
202 RGB(0, 0, 255), // BLUE | INTENSITY
203 RGB(0, 255, 0), // GREEN | INTENSITY
204 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
205 RGB(255, 0, 0), // RED | INTENSITY
206 RGB(255, 0, 255), // BLUE | RED | INTENSITY
207 RGB(255, 255, 0), // GREEN | RED | INTENSITY
208 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
209 };
210
211 /*
212 * Console interface -- VGA-mode-agnostic
213 */
214 // WARNING! This structure *MUST BE* in sync with the one in consrv/include/conio_winsrv.h
215 typedef struct _CHAR_CELL
216 {
217 CHAR Char;
218 BYTE Attributes;
219 } CHAR_CELL, *PCHAR_CELL;
220 C_ASSERT(sizeof(CHAR_CELL) == 2);
221
222 static PVOID ConsoleFramebuffer = NULL; // Active framebuffer, points to
223 // either TextFramebuffer or a
224 // valid graphics framebuffer.
225 static HPALETTE TextPaletteHandle = NULL;
226 static HPALETTE PaletteHandle = NULL;
227
228 static HANDLE StartEvent = NULL;
229 static HANDLE EndEvent = NULL;
230 static HANDLE AnotherEvent = NULL;
231
232 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo;
233 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo;
234
235
236 static HANDLE ScreenBufferHandle = NULL;
237 static PVOID OldConsoleFramebuffer = NULL;
238
239
240 /*
241 * Text mode -- we always keep a valid text mode framebuffer
242 * even if we are in graphics mode. This is needed in order
243 * to keep a consistent VGA state. However, each time the VGA
244 * detaches from the console (and reattaches to it later on),
245 * this text mode framebuffer is recreated.
246 */
247 static HANDLE TextConsoleBuffer = NULL;
248 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
249 static COORD TextResolution = {0};
250 static PCHAR_CELL TextFramebuffer = NULL;
251
252 /*
253 * Graphics mode
254 */
255 static HANDLE GraphicsConsoleBuffer = NULL;
256 static PVOID GraphicsFramebuffer = NULL;
257 static HANDLE ConsoleMutex = NULL;
258 /* DoubleVision support */
259 static BOOLEAN DoubleWidth = FALSE;
260 static BOOLEAN DoubleHeight = FALSE;
261
262
263 /*
264 * VGA Hardware
265 */
266 static BYTE VgaMemory[VGA_NUM_BANKS * SVGA_BANK_SIZE];
267
268 static BYTE VgaLatchRegisters[VGA_NUM_BANKS] = {0, 0, 0, 0};
269
270 static BYTE VgaMiscRegister;
271 static BYTE VgaFeatureRegister;
272
273 static BYTE VgaSeqIndex = VGA_SEQ_RESET_REG;
274 static BYTE VgaSeqRegisters[SVGA_SEQ_MAX_REG];
275
276 static BYTE VgaCrtcIndex = VGA_CRTC_HORZ_TOTAL_REG;
277 static BYTE VgaCrtcRegisters[SVGA_CRTC_MAX_REG];
278
279 static BYTE VgaGcIndex = VGA_GC_RESET_REG;
280 static BYTE VgaGcRegisters[SVGA_GC_MAX_REG];
281
282 static BOOLEAN VgaAcLatch = FALSE;
283 static BOOLEAN VgaAcPalDisable = TRUE;
284 static BYTE VgaAcIndex = VGA_AC_PAL_0_REG;
285 static BYTE VgaAcRegisters[VGA_AC_MAX_REG];
286
287 static BYTE VgaDacMask = 0xFF;
288 static BYTE VgaDacLatchCounter = 0;
289 static BYTE VgaDacLatch[3];
290
291 static BOOLEAN VgaDacReadWrite = FALSE;
292 static WORD VgaDacIndex = 0;
293 static BYTE VgaDacRegisters[VGA_PALETTE_SIZE];
294
295 // static VGA_REGISTERS VgaRegisters;
296
297 static ULONGLONG VerticalRetraceCycle = 0ULL;
298 static ULONGLONG HorizontalRetraceCycle = 0ULL;
299 static PHARDWARE_TIMER VSyncTimer;
300 static PHARDWARE_TIMER HSyncTimer;
301
302 static BOOLEAN NeedsUpdate = FALSE;
303 static BOOLEAN ModeChanged = FALSE;
304 static BOOLEAN CursorChanged = FALSE;
305 static BOOLEAN PaletteChanged = FALSE;
306
307 static UINT SvgaHdrCounter = 0;
308 static BYTE SvgaHiddenRegister = 0;
309
310 typedef enum _SCREEN_MODE
311 {
312 TEXT_MODE,
313 GRAPHICS_MODE
314 } SCREEN_MODE, *PSCREEN_MODE;
315
316 static SCREEN_MODE ScreenMode = TEXT_MODE;
317 static COORD CurrResolution = {0};
318
319 static SMALL_RECT UpdateRectangle = { 0, 0, 0, 0 };
320
321 /* RegisterConsoleVDM EMULATION ***********************************************/
322
323 #include <ntddvdeo.h>
324
325 #ifdef USE_REAL_REGISTERCONSOLEVDM
326
327 #define __RegisterConsoleVDM RegisterConsoleVDM
328 #define __InvalidateConsoleDIBits InvalidateConsoleDIBits
329
330 #else
331
332 /*
333 * This private buffer, per-console, is used by
334 * RegisterConsoleVDM and InvalidateConsoleDIBits.
335 */
336 static COORD VDMBufferSize = {0};
337 static PCHAR_CELL VDMBuffer = NULL;
338
339 static PCHAR_INFO CharBuff = NULL; // This is a hack, which is unneeded
340 // for the real RegisterConsoleVDM and
341 // InvalidateConsoleDIBits
342
343 BOOL
344 WINAPI
345 __RegisterConsoleVDM(IN DWORD dwRegisterFlags,
346 IN HANDLE hStartHardwareEvent,
347 IN HANDLE hEndHardwareEvent,
348 IN HANDLE hErrorHardwareEvent,
349 IN DWORD dwUnusedVar,
350 OUT LPDWORD lpVideoStateLength,
351 OUT PVOID* lpVideoState, // PVIDEO_HARDWARE_STATE_HEADER*
352 IN PVOID lpUnusedBuffer,
353 IN DWORD dwUnusedBufferLength,
354 IN COORD dwVDMBufferSize,
355 OUT PVOID* lpVDMBuffer)
356 {
357 UNREFERENCED_PARAMETER(hErrorHardwareEvent);
358 UNREFERENCED_PARAMETER(dwUnusedVar);
359 UNREFERENCED_PARAMETER(lpVideoStateLength);
360 UNREFERENCED_PARAMETER(lpVideoState);
361 UNREFERENCED_PARAMETER(lpUnusedBuffer);
362 UNREFERENCED_PARAMETER(dwUnusedBufferLength);
363
364 SetLastError(0);
365 DPRINT1("__RegisterConsoleVDM(%d)\n", dwRegisterFlags);
366
367 if (lpVDMBuffer == NULL) return FALSE;
368
369 if (dwRegisterFlags != 0)
370 {
371 // if (hStartHardwareEvent == NULL || hEndHardwareEvent == NULL) return FALSE;
372 if (VDMBuffer != NULL) return FALSE;
373
374 VDMBufferSize = dwVDMBufferSize;
375
376 /* HACK: Cache -- to be removed in the real implementation */
377 CharBuff = RtlAllocateHeap(RtlGetProcessHeap(),
378 HEAP_ZERO_MEMORY,
379 VDMBufferSize.X * VDMBufferSize.Y
380 * sizeof(*CharBuff));
381 ASSERT(CharBuff);
382
383 VDMBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
384 HEAP_ZERO_MEMORY,
385 VDMBufferSize.X * VDMBufferSize.Y
386 * sizeof(*VDMBuffer));
387 *lpVDMBuffer = VDMBuffer;
388 return (VDMBuffer != NULL);
389 }
390 else
391 {
392 /* HACK: Cache -- to be removed in the real implementation */
393 if (CharBuff) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff);
394 CharBuff = NULL;
395
396 if (VDMBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, VDMBuffer);
397 VDMBuffer = NULL;
398
399 VDMBufferSize.X = VDMBufferSize.Y = 0;
400
401 return TRUE;
402 }
403 }
404
405 BOOL
406 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput,
407 IN PSMALL_RECT lpRect)
408 {
409 if ((hConsoleOutput == TextConsoleBuffer) && (VDMBuffer != NULL))
410 {
411 /* HACK: Write the cached data to the console */
412
413 COORD Origin = { lpRect->Left, lpRect->Top };
414 SHORT i, j;
415
416 ASSERT(CharBuff);
417
418 for (i = 0; i < VDMBufferSize.Y; i++)
419 {
420 for (j = 0; j < VDMBufferSize.X; j++)
421 {
422 CharBuff[i * VDMBufferSize.X + j].Char.AsciiChar = VDMBuffer[i * VDMBufferSize.X + j].Char;
423 CharBuff[i * VDMBufferSize.X + j].Attributes = VDMBuffer[i * VDMBufferSize.X + j].Attributes;
424 }
425 }
426
427 WriteConsoleOutputA(hConsoleOutput,
428 CharBuff,
429 VDMBufferSize,
430 Origin,
431 lpRect);
432 }
433
434 return InvalidateConsoleDIBits(hConsoleOutput, lpRect);
435 }
436
437 #endif
438
439 /* PRIVATE FUNCTIONS **********************************************************/
440
441 static inline DWORD VgaGetAddressSize(VOID);
442 static VOID VgaUpdateTextCursor(VOID);
443
444 static inline DWORD VgaGetVideoBaseAddress(VOID)
445 {
446 return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
447 }
448
449 static VOID VgaUpdateCursorPosition(VOID)
450 {
451 /*
452 * Update the cursor position in the VGA registers.
453 */
454 WORD Offset = ConsoleInfo.dwCursorPosition.Y * TextResolution.X +
455 ConsoleInfo.dwCursorPosition.X;
456
457 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG] = LOBYTE(Offset);
458 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG] = HIBYTE(Offset);
459
460 VgaUpdateTextCursor();
461 }
462
463 static VOID ResizeTextConsole(PCOORD Resolution, PSMALL_RECT WindowSize OPTIONAL)
464 {
465 BOOL Success;
466 SMALL_RECT ConRect;
467 SHORT oldWidth, oldHeight;
468
469 /*
470 * Use this trick to effectively resize the console buffer and window,
471 * because:
472 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
473 * is smaller than the current console window size, and:
474 * - SetConsoleWindowInfo fails if the new console window size is larger
475 * than the current console screen buffer size.
476 */
477
478
479 /* Retrieve the latest console information */
480 GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
481
482 oldWidth = ConsoleInfo.srWindow.Right - ConsoleInfo.srWindow.Left + 1;
483 oldHeight = ConsoleInfo.srWindow.Bottom - ConsoleInfo.srWindow.Top + 1;
484
485 /*
486 * If the current console window is too large to hold the full contents
487 * of the new screen buffer, resize it first.
488 */
489 if (oldWidth > Resolution->X || oldHeight > Resolution->Y)
490 {
491 //
492 // NOTE: This is not a problem if we move the window back to (0,0)
493 // because when we resize the screen buffer, the window will move back
494 // to where the cursor is. Or, if the screen buffer is not resized,
495 // when we readjust again the window, we will move back to a correct
496 // position. This is what we wanted after all...
497 //
498
499 ConRect.Left = ConRect.Top = 0;
500 ConRect.Right = ConRect.Left + min(oldWidth , Resolution->X) - 1;
501 ConRect.Bottom = ConRect.Top + min(oldHeight, Resolution->Y) - 1;
502
503 Success = SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
504 if (!Success) DPRINT1("(resize) SetConsoleWindowInfo(1) failed with error %d\n", GetLastError());
505 }
506
507 /* Resize the screen buffer if needed */
508 if (Resolution->X != ConsoleInfo.dwSize.X || Resolution->Y != ConsoleInfo.dwSize.Y)
509 {
510 /*
511 * SetConsoleScreenBufferSize automatically takes into account the current
512 * cursor position when it computes starting which row it should copy text
513 * when resizing the sceenbuffer, and scrolls the console window such that
514 * the cursor is placed in it again. We therefore do not need to care about
515 * the cursor position and do the maths ourselves.
516 */
517 Success = SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
518 if (!Success) DPRINT1("(resize) SetConsoleScreenBufferSize failed with error %d\n", GetLastError());
519
520 /*
521 * Setting a new screen buffer size can change other information,
522 * so update the saved console information.
523 */
524 GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
525 }
526
527 if (!WindowSize)
528 {
529 ConRect.Left = 0;
530 ConRect.Right = ConRect.Left + Resolution->X - 1;
531 ConRect.Bottom = max(ConsoleInfo.dwCursorPosition.Y, Resolution->Y - 1);
532 ConRect.Top = ConRect.Bottom - Resolution->Y + 1;
533
534 // NOTE: We may take ConsoleInfo.dwMaximumWindowSize into account
535 }
536 else
537 {
538 ConRect.Left = ConRect.Top = 0;
539 ConRect.Right = ConRect.Left + WindowSize->Right - WindowSize->Left;
540 ConRect.Bottom = ConRect.Top + WindowSize->Bottom - WindowSize->Top ;
541 }
542
543 Success = SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
544 if (!Success) DPRINT1("(resize) SetConsoleWindowInfo(2) failed with error %d\n", GetLastError());
545
546 /* Update the saved console information */
547 GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
548 }
549
550 static BOOL VgaAttachToConsoleInternal(PCOORD Resolution)
551 {
552 BOOL Success;
553 ULONG Length = 0;
554 PVIDEO_HARDWARE_STATE_HEADER State;
555
556 #ifdef USE_REAL_REGISTERCONSOLEVDM
557 PCHAR_INFO CharBuff = NULL;
558 #endif
559 SHORT i, j;
560 DWORD AddressSize, ScanlineSize;
561 DWORD Address = 0;
562 DWORD CurrentAddr;
563 SMALL_RECT ConRect;
564 COORD Origin = { 0, 0 };
565
566 ASSERT(TextFramebuffer == NULL);
567
568 TextResolution = *Resolution;
569
570 /*
571 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
572 * in the two following APIs:
573 * SrvRegisterConsoleVDM (corresponding Win32 API: RegisterConsoleVDM)
574 * SrvVDMConsoleOperation (corresponding Win32 API: VDMConsoleOperation)
575 * to check whether the current process is a VDM process, and fails otherwise
576 * with the error 0xC0000022 (STATUS_ACCESS_DENIED).
577 *
578 * It is worth it to notice that also basesrv.dll does the same only for the
579 * BaseSrvIsFirstVDM API...
580 */
581
582 /* Register with the console server */
583 Success =
584 __RegisterConsoleVDM(1,
585 StartEvent,
586 EndEvent,
587 AnotherEvent, // NULL,
588 0,
589 &Length, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
590 (PVOID*)&State, // NULL,
591 NULL,
592 0,
593 TextResolution,
594 (PVOID*)&TextFramebuffer);
595 if (!Success)
596 {
597 DisplayMessage(L"RegisterConsoleVDM failed with error %d\n", GetLastError());
598 EmulatorTerminate();
599 return FALSE;
600 }
601
602 #ifdef USE_REAL_REGISTERCONSOLEVDM
603 CharBuff = RtlAllocateHeap(RtlGetProcessHeap(),
604 HEAP_ZERO_MEMORY,
605 TextResolution.X * TextResolution.Y
606 * sizeof(*CharBuff));
607 ASSERT(CharBuff);
608 #endif
609
610 /* Resize the console */
611 ResizeTextConsole(Resolution, NULL);
612
613 /* Update the saved console information */
614 GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
615
616 /*
617 * Copy console data into VGA memory
618 */
619
620 /* Read the data from the console into the framebuffer... */
621 ConRect.Left = ConRect.Top = 0;
622 ConRect.Right = TextResolution.X;
623 ConRect.Bottom = TextResolution.Y;
624
625 ReadConsoleOutputA(TextConsoleBuffer,
626 CharBuff,
627 TextResolution,
628 Origin,
629 &ConRect);
630
631 /* ... and copy the framebuffer into the VGA memory */
632 AddressSize = VgaGetAddressSize();
633 ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
634
635 /* Loop through the scanlines */
636 for (i = 0; i < TextResolution.Y; i++)
637 {
638 /* Loop through the characters */
639 for (j = 0; j < TextResolution.X; j++)
640 {
641 CurrentAddr = LOWORD((Address + j) * AddressSize);
642
643 /* Store the character in plane 0 */
644 VgaMemory[CurrentAddr] = CharBuff[i * TextResolution.X + j].Char.AsciiChar;
645
646 /* Store the attribute in plane 1 */
647 VgaMemory[CurrentAddr + VGA_BANK_SIZE] = (BYTE)CharBuff[i * TextResolution.X + j].Attributes;
648 }
649
650 /* Move to the next scanline */
651 Address += ScanlineSize;
652 }
653
654 #ifdef USE_REAL_REGISTERCONSOLEVDM
655 if (CharBuff) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff);
656 #endif
657
658 VgaUpdateCursorPosition();
659
660 return TRUE;
661 }
662
663 static VOID VgaDetachFromConsoleInternal(VOID)
664 {
665 ULONG dummyLength;
666 PVOID dummyPtr;
667 COORD dummySize = {0};
668
669 /* Deregister with the console server */
670 __RegisterConsoleVDM(0,
671 NULL,
672 NULL,
673 NULL,
674 0,
675 &dummyLength,
676 &dummyPtr,
677 NULL,
678 0,
679 dummySize,
680 &dummyPtr);
681
682 TextFramebuffer = NULL;
683 }
684
685 static BOOL IsConsoleHandle(HANDLE hHandle)
686 {
687 DWORD dwMode;
688
689 /* Check whether the handle may be that of a console... */
690 if ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR)
691 return FALSE;
692
693 /*
694 * It may be. Perform another test... The idea comes from the
695 * MSDN description of the WriteConsole API:
696 *
697 * "WriteConsole fails if it is used with a standard handle
698 * that is redirected to a file. If an application processes
699 * multilingual output that can be redirected, determine whether
700 * the output handle is a console handle (one method is to call
701 * the GetConsoleMode function and check whether it succeeds).
702 * If the handle is a console handle, call WriteConsole. If the
703 * handle is not a console handle, the output is redirected and
704 * you should call WriteFile to perform the I/O."
705 */
706 return GetConsoleMode(hHandle, &dwMode);
707 }
708
709 static inline DWORD VgaGetAddressSize(VOID)
710 {
711 if (VgaCrtcRegisters[VGA_CRTC_UNDERLINE_REG] & VGA_CRTC_UNDERLINE_DWORD)
712 {
713 /* Double-word addressing */
714 return 4; // sizeof(DWORD)
715 }
716 else if (VgaCrtcRegisters[VGA_CRTC_MODE_CONTROL_REG] & VGA_CRTC_MODE_CONTROL_BYTE)
717 {
718 /* Byte addressing */
719 return 1; // sizeof(BYTE)
720 }
721 else
722 {
723 /* Word addressing */
724 return 2; // sizeof(WORD)
725 }
726 }
727
728 static inline DWORD VgaTranslateReadAddress(DWORD Address)
729 {
730 DWORD Offset = LOWORD(Address - VgaGetVideoBaseAddress());
731 BYTE Plane;
732
733 /* Check for chain-4 and odd-even mode */
734 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
735 {
736 /* The lowest two bits are the plane number */
737 Plane = Offset & 0x03;
738 Offset &= ~3;
739 }
740 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
741 {
742 /* The LSB is the plane number */
743 Plane = Offset & 0x01;
744 Offset &= ~1;
745 }
746 else
747 {
748 /* Use the read mode */
749 Plane = VgaGcRegisters[VGA_GC_READ_MAP_SEL_REG] & 0x03;
750 }
751
752 /* Return the offset on plane 0 for read mode 1 */
753 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_READ) return Offset;
754 else return Offset + Plane * VGA_BANK_SIZE;
755 }
756
757 static inline DWORD VgaTranslateWriteAddress(DWORD Address)
758 {
759 DWORD Offset = LOWORD(Address - VgaGetVideoBaseAddress());
760
761 /* Check for chain-4 and odd-even mode */
762 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
763 {
764 /* Clear the lowest two bits since they're used to select the bank */
765 Offset &= ~3;
766 }
767 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
768 {
769 /* Clear the lowest bit since it's used to select odd/even */
770 Offset &= ~1;
771 }
772
773 /* Return the offset on plane 0 */
774 return Offset;
775 }
776
777 static inline BYTE VgaTranslateByteForWriting(BYTE Data, BYTE Plane)
778 {
779 BYTE WriteMode = VgaGcRegisters[VGA_GC_MODE_REG] & 0x03;
780 BYTE BitMask = VgaGcRegisters[VGA_GC_BITMASK_REG];
781
782 if (WriteMode == 1)
783 {
784 /* In write mode 1 just return the latch register */
785 return VgaLatchRegisters[Plane];
786 }
787
788 if (WriteMode != 2)
789 {
790 /* Write modes 0 and 3 rotate the data to the right first */
791 BYTE RotateCount = VgaGcRegisters[VGA_GC_ROTATE_REG] & 0x07;
792 Data = LOBYTE(((DWORD)Data >> RotateCount) | ((DWORD)Data << (8 - RotateCount)));
793 }
794 else
795 {
796 /* Write mode 2 expands the appropriate bit to all 8 bits */
797 Data = (Data & (1 << Plane)) ? 0xFF : 0x00;
798 }
799
800 if (WriteMode == 0)
801 {
802 /*
803 * In write mode 0, the enable set/reset register decides if the
804 * set/reset bit should be expanded to all 8 bits.
805 */
806 if (VgaGcRegisters[VGA_GC_ENABLE_RESET_REG] & (1 << Plane))
807 {
808 /* Copy the bit from the set/reset register to all 8 bits */
809 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
810 }
811 }
812
813 if (WriteMode != 3)
814 {
815 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
816 BYTE LogicalOperation = (VgaGcRegisters[VGA_GC_ROTATE_REG] >> 3) & 0x03;
817
818 if (LogicalOperation == 1) Data &= VgaLatchRegisters[Plane];
819 else if (LogicalOperation == 2) Data |= VgaLatchRegisters[Plane];
820 else if (LogicalOperation == 3) Data ^= VgaLatchRegisters[Plane];
821 }
822 else
823 {
824 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
825 BitMask &= Data;
826
827 /* Then we expand the bit in the set/reset field */
828 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
829 }
830
831 /* Bits cleared in the bitmask are replaced with latch register bits */
832 Data = (Data & BitMask) | (VgaLatchRegisters[Plane] & (~BitMask));
833
834 /* Return the byte */
835 return Data;
836 }
837
838 static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column)
839 {
840 /* Check if this is the first time the rectangle is updated */
841 if (!NeedsUpdate)
842 {
843 UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT;
844 UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT;
845 }
846
847 /* Expand the rectangle to include the point */
848 UpdateRectangle.Left = min(UpdateRectangle.Left, Column);
849 UpdateRectangle.Right = max(UpdateRectangle.Right, Column);
850 UpdateRectangle.Top = min(UpdateRectangle.Top, Row);
851 UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Row);
852
853 /* Set the update request flag */
854 NeedsUpdate = TRUE;
855 }
856
857 static inline ULONG VgaGetClockFrequency(VOID)
858 {
859 BYTE Numerator, Denominator;
860
861 if (VgaSeqRegisters[SVGA_SEQ_MCLK_REG] & SVGA_SEQ_MCLK_VCLK)
862 {
863 /* The VCLK is being generated using the MCLK */
864 ULONG Clock = (VGA_CLOCK_BASE * (VgaSeqRegisters[SVGA_SEQ_MCLK_REG] & 0x3F)) >> 3;
865
866 if (VgaSeqRegisters[SVGA_SEQ_VCLK3_DENOMINATOR_REG] & 1)
867 {
868 /* Use only half of the MCLK as the VCLK */
869 Clock >>= 1;
870 }
871
872 return Clock;
873 }
874
875 switch ((VgaMiscRegister >> 2) & 3)
876 {
877 case 0:
878 {
879 Numerator = VgaSeqRegisters[SVGA_SEQ_VCLK0_NUMERATOR_REG];
880 Denominator = VgaSeqRegisters[SVGA_SEQ_VCLK0_DENOMINATOR_REG];
881 break;
882 }
883
884 case 1:
885 {
886 Numerator = VgaSeqRegisters[SVGA_SEQ_VCLK1_NUMERATOR_REG];
887 Denominator = VgaSeqRegisters[SVGA_SEQ_VCLK1_DENOMINATOR_REG];
888 break;
889 }
890
891 case 2:
892 {
893 Numerator = VgaSeqRegisters[SVGA_SEQ_VCLK2_NUMERATOR_REG];
894 Denominator = VgaSeqRegisters[SVGA_SEQ_VCLK2_DENOMINATOR_REG];
895 break;
896 }
897
898 case 3:
899 {
900 Numerator = VgaSeqRegisters[SVGA_SEQ_VCLK3_NUMERATOR_REG];
901 Denominator = VgaSeqRegisters[SVGA_SEQ_VCLK3_DENOMINATOR_REG];
902 break;
903 }
904 }
905
906 /* The numerator is 7-bit */
907 Numerator &= ~(1 << 7);
908
909 /* If bit 7 is clear, the denominator is 5-bit */
910 if (!(Denominator & (1 << 7))) Denominator &= ~(1 << 6);
911
912 /* Bit 0 of the denominator is the post-scalar bit */
913 if (Denominator & 1) Denominator &= ~1;
914 else Denominator >>= 1;
915
916 /* Return the clock frequency in Hz */
917 return (VGA_CLOCK_BASE * Numerator) / Denominator;
918 }
919
920 static VOID VgaResetSequencer(VOID)
921 {
922 /* Lock extended SVGA registers */
923 VgaSeqRegisters[SVGA_SEQ_UNLOCK_REG] = SVGA_SEQ_LOCKED;
924
925 /* Initialize the VCLKs */
926 VgaSeqRegisters[SVGA_SEQ_VCLK0_NUMERATOR_REG] = 0x66;
927 VgaSeqRegisters[SVGA_SEQ_VCLK0_DENOMINATOR_REG] = 0x3B;
928 VgaSeqRegisters[SVGA_SEQ_VCLK1_NUMERATOR_REG] = 0x5B;
929 VgaSeqRegisters[SVGA_SEQ_VCLK1_DENOMINATOR_REG] = 0x2F;
930 VgaSeqRegisters[SVGA_SEQ_VCLK2_NUMERATOR_REG] = 0x45;
931 VgaSeqRegisters[SVGA_SEQ_VCLK2_DENOMINATOR_REG] = 0x30;
932 VgaSeqRegisters[SVGA_SEQ_VCLK3_NUMERATOR_REG] = 0x7E;
933 VgaSeqRegisters[SVGA_SEQ_VCLK3_DENOMINATOR_REG] = 0x33;
934
935 /* 50 MHz MCLK, not being used as the VCLK */
936 VgaSeqRegisters[SVGA_SEQ_MCLK_REG] = 0x1C;
937 }
938
939 static VOID VgaRestoreDefaultPalette(PPALETTEENTRY Entries, USHORT NumOfEntries)
940 {
941 USHORT i;
942
943 /* Copy the colors of the default palette to the DAC and console palette */
944 for (i = 0; i < NumOfEntries; i++)
945 {
946 /* Set the palette entries */
947 Entries[i].peRed = GetRValue(VgaDefaultPalette[i]);
948 Entries[i].peGreen = GetGValue(VgaDefaultPalette[i]);
949 Entries[i].peBlue = GetBValue(VgaDefaultPalette[i]);
950 Entries[i].peFlags = 0;
951
952 /* Set the DAC registers */
953 VgaDacRegisters[i * 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette[i]));
954 VgaDacRegisters[i * 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette[i]));
955 VgaDacRegisters[i * 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette[i]));
956 }
957 }
958
959 static BOOLEAN VgaInitializePalette(VOID)
960 {
961 UINT i;
962 BOOLEAN Result = FALSE;
963 LPLOGPALETTE Palette, TextPalette;
964
965 /* Allocate storage space for the palettes */
966 Palette = RtlAllocateHeap(RtlGetProcessHeap(),
967 HEAP_ZERO_MEMORY,
968 sizeof(LOGPALETTE) +
969 VGA_MAX_COLORS * sizeof(PALETTEENTRY));
970 TextPalette = RtlAllocateHeap(RtlGetProcessHeap(),
971 HEAP_ZERO_MEMORY,
972 sizeof(LOGPALETTE) +
973 (VGA_AC_PAL_F_REG + 1) * sizeof(PALETTEENTRY));
974 if ((Palette == NULL) || (TextPalette == NULL)) goto Cleanup;
975
976 /* Initialize the palettes */
977 Palette->palVersion = TextPalette->palVersion = 0x0300;
978 Palette->palNumEntries = VGA_MAX_COLORS;
979 TextPalette->palNumEntries = VGA_AC_PAL_F_REG + 1;
980
981 /* Restore the default graphics palette */
982 VgaRestoreDefaultPalette(Palette->palPalEntry, Palette->palNumEntries);
983
984 /* Set the default text palette */
985 for (i = 0; i < TextPalette->palNumEntries; i++)
986 {
987 /* Set the palette entries */
988 TextPalette->palPalEntry[i].peRed = GetRValue(ConsoleColors[i]);
989 TextPalette->palPalEntry[i].peGreen = GetGValue(ConsoleColors[i]);
990 TextPalette->palPalEntry[i].peBlue = GetBValue(ConsoleColors[i]);
991 TextPalette->palPalEntry[i].peFlags = 0;
992 }
993
994 /* Create the palettes */
995 PaletteHandle = CreatePalette(Palette);
996 TextPaletteHandle = CreatePalette(TextPalette);
997
998 if (PaletteHandle != NULL && TextPaletteHandle != NULL)
999 {
1000 /* The palettes have been created successfully */
1001 Result = TRUE;
1002 }
1003
1004 Cleanup:
1005 /* Free the palettes */
1006 if (Palette) RtlFreeHeap(RtlGetProcessHeap(), 0, Palette);
1007 if (TextPalette) RtlFreeHeap(RtlGetProcessHeap(), 0, TextPalette);
1008
1009 if (!Result)
1010 {
1011 /* Something failed, delete the palettes */
1012 if (PaletteHandle) DeleteObject(PaletteHandle);
1013 if (TextPaletteHandle) DeleteObject(TextPaletteHandle);
1014 }
1015
1016 return Result;
1017 }
1018
1019 static VOID VgaResetPalette(VOID)
1020 {
1021 PALETTEENTRY Entries[VGA_MAX_COLORS];
1022
1023 /* Restore the default palette */
1024 VgaRestoreDefaultPalette(Entries, VGA_MAX_COLORS);
1025 SetPaletteEntries(PaletteHandle, 0, VGA_MAX_COLORS, Entries);
1026 PaletteChanged = TRUE;
1027 }
1028
1029 static VOID VgaSetActiveScreenBuffer(HANDLE ScreenBuffer)
1030 {
1031 ASSERT(ScreenBuffer);
1032
1033 /* Set the active buffer and reattach the VDM UI to it */
1034 SetConsoleActiveScreenBuffer(ScreenBuffer);
1035 ConsoleReattach(ScreenBuffer);
1036 }
1037
1038 static BOOL VgaEnterGraphicsMode(PCOORD Resolution)
1039 {
1040 DWORD i;
1041 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo;
1042 BYTE BitmapInfoBuffer[VGA_BITMAP_INFO_SIZE];
1043 LPBITMAPINFO BitmapInfo = (LPBITMAPINFO)BitmapInfoBuffer;
1044 LPWORD PaletteIndex = (LPWORD)(BitmapInfo->bmiColors);
1045
1046 LONG Width = Resolution->X;
1047 LONG Height = Resolution->Y;
1048
1049 /* Use DoubleVision mode if the resolution is too small */
1050 DoubleWidth = (Width < VGA_MINIMUM_WIDTH);
1051 if (DoubleWidth) Width *= 2;
1052 DoubleHeight = (Height < VGA_MINIMUM_HEIGHT);
1053 if (DoubleHeight) Height *= 2;
1054
1055 /* Fill the bitmap info header */
1056 RtlZeroMemory(&BitmapInfo->bmiHeader, sizeof(BitmapInfo->bmiHeader));
1057 BitmapInfo->bmiHeader.biSize = sizeof(BitmapInfo->bmiHeader);
1058 BitmapInfo->bmiHeader.biWidth = Width;
1059 BitmapInfo->bmiHeader.biHeight = Height;
1060 BitmapInfo->bmiHeader.biBitCount = 8;
1061 BitmapInfo->bmiHeader.biPlanes = 1;
1062 BitmapInfo->bmiHeader.biCompression = BI_RGB;
1063 BitmapInfo->bmiHeader.biSizeImage = Width * Height /* * 1 == biBitCount / 8 */;
1064
1065 /* Fill the palette data */
1066 for (i = 0; i < (VGA_PALETTE_SIZE / 3); i++) PaletteIndex[i] = (WORD)i;
1067
1068 /* Fill the console graphics buffer info */
1069 GraphicsBufferInfo.dwBitMapInfoLength = VGA_BITMAP_INFO_SIZE;
1070 GraphicsBufferInfo.lpBitMapInfo = BitmapInfo;
1071 GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS;
1072
1073 /* Create the buffer */
1074 GraphicsConsoleBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
1075 FILE_SHARE_READ | FILE_SHARE_WRITE,
1076 NULL,
1077 CONSOLE_GRAPHICS_BUFFER,
1078 &GraphicsBufferInfo);
1079 if (GraphicsConsoleBuffer == INVALID_HANDLE_VALUE) return FALSE;
1080
1081 /* Save the framebuffer address and mutex */
1082 GraphicsFramebuffer = GraphicsBufferInfo.lpBitMap;
1083 ConsoleMutex = GraphicsBufferInfo.hMutex;
1084
1085 /* Clear the framebuffer */
1086 RtlZeroMemory(GraphicsFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
1087
1088 /* Set the active buffer */
1089 VgaSetActiveScreenBuffer(GraphicsConsoleBuffer);
1090
1091 /* The active framebuffer is now the graphics framebuffer */
1092 ConsoleFramebuffer = GraphicsFramebuffer;
1093
1094 /* Set the graphics mode palette */
1095 SetConsolePalette(GraphicsConsoleBuffer,
1096 PaletteHandle,
1097 SYSPAL_NOSTATIC256);
1098
1099 /* Set the screen mode flag */
1100 ScreenMode = GRAPHICS_MODE;
1101
1102 return TRUE;
1103 }
1104
1105 static VOID VgaLeaveGraphicsMode(VOID)
1106 {
1107 /* Release the console framebuffer mutex */
1108 ReleaseMutex(ConsoleMutex);
1109
1110 /* Switch back to the default console text buffer */
1111 // VgaSetActiveScreenBuffer(TextConsoleBuffer);
1112
1113 /* Cleanup the video data */
1114 CloseHandle(ConsoleMutex);
1115 ConsoleMutex = NULL;
1116 GraphicsFramebuffer = NULL;
1117 CloseHandle(GraphicsConsoleBuffer);
1118 GraphicsConsoleBuffer = NULL;
1119
1120 /* Reset the active framebuffer */
1121 ConsoleFramebuffer = NULL;
1122
1123 DoubleWidth = FALSE;
1124 DoubleHeight = FALSE;
1125 }
1126
1127 static BOOL VgaEnterTextMode(PCOORD Resolution)
1128 {
1129 /* Switch to the text buffer */
1130 // FIXME: Wouldn't it be preferrable to switch to it AFTER we reset everything??
1131 VgaSetActiveScreenBuffer(TextConsoleBuffer);
1132
1133 /* Adjust the text framebuffer if we changed the resolution */
1134 if (TextResolution.X != Resolution->X ||
1135 TextResolution.Y != Resolution->Y)
1136 {
1137 VgaDetachFromConsoleInternal();
1138
1139 /*
1140 * VgaAttachToConsoleInternal sets TextResolution
1141 * to the new resolution and updates ConsoleInfo.
1142 */
1143 if (!VgaAttachToConsoleInternal(Resolution))
1144 {
1145 DisplayMessage(L"An unexpected error occurred!\n");
1146 EmulatorTerminate();
1147 return FALSE;
1148 }
1149 }
1150 else
1151 {
1152 VgaUpdateCursorPosition();
1153 }
1154
1155 /* The active framebuffer is now the text framebuffer */
1156 ConsoleFramebuffer = TextFramebuffer;
1157
1158 /*
1159 * Set the text mode palette.
1160 *
1161 * INFORMATION: This call should fail on Windows (and therefore
1162 * we get the default palette and our external behaviour is
1163 * just like Windows' one), but it should success on ReactOS
1164 * (so that we get console palette changes even for text-mode
1165 * screen buffers, which is a new feature on ReactOS).
1166 */
1167 SetConsolePalette(TextConsoleBuffer,
1168 TextPaletteHandle,
1169 SYSPAL_NOSTATIC256);
1170
1171 /* Set the screen mode flag */
1172 ScreenMode = TEXT_MODE;
1173
1174 return TRUE;
1175 }
1176
1177 static VOID VgaLeaveTextMode(VOID)
1178 {
1179 /* Reset the active framebuffer */
1180 ConsoleFramebuffer = NULL;
1181 }
1182
1183 static VOID VgaChangeMode(VOID)
1184 {
1185 COORD NewResolution = VgaGetDisplayResolution();
1186 SCREEN_MODE NewScreenMode =
1187 !(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) ? TEXT_MODE
1188 : GRAPHICS_MODE;
1189
1190 /*
1191 * Do not switch to a different screen mode + resolution if the new settings
1192 * are the same as the old ones. Just repaint the full screen.
1193 */
1194 if ((ScreenMode == NewScreenMode) && // CurrResolution == NewResolution
1195 (CurrResolution.X == NewResolution.X && CurrResolution.Y == NewResolution.Y))
1196 {
1197 goto Quit;
1198 }
1199
1200 // FIXME: Wouldn't it be preferrable to switch to the new console SB
1201 // *ONLY* if we succeeded in setting the new mode??
1202
1203 /* Leave the current video mode */
1204 if (ScreenMode == GRAPHICS_MODE)
1205 VgaLeaveGraphicsMode();
1206 else
1207 VgaLeaveTextMode();
1208
1209 /* Update the current resolution */
1210 CurrResolution = NewResolution;
1211
1212 /* The new screen mode will be updated via the VgaEnterText/GraphicsMode functions */
1213
1214 /* Check if the new mode is alphanumeric */
1215 if (NewScreenMode == TEXT_MODE)
1216 {
1217 /* Enter new text mode */
1218 if (!VgaEnterTextMode(&CurrResolution))
1219 {
1220 DisplayMessage(L"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
1221 EmulatorTerminate();
1222 return;
1223 }
1224 }
1225 else
1226 {
1227 /* Enter graphics mode */
1228 if (!VgaEnterGraphicsMode(&CurrResolution))
1229 {
1230 DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
1231 EmulatorTerminate();
1232 return;
1233 }
1234 }
1235
1236 Quit:
1237
1238 /* Trigger a full update of the screen */
1239 NeedsUpdate = TRUE;
1240 UpdateRectangle.Left = 0;
1241 UpdateRectangle.Top = 0;
1242 UpdateRectangle.Right = CurrResolution.X;
1243 UpdateRectangle.Bottom = CurrResolution.Y;
1244
1245 /* Reset the mode change flag */
1246 ModeChanged = FALSE;
1247 }
1248
1249 static VOID VgaUpdateFramebuffer(VOID)
1250 {
1251 SHORT i, j, k;
1252 DWORD AddressSize = VgaGetAddressSize();
1253 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1254 BYTE PresetRowScan = VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] & 0x1F;
1255 BYTE BytePanning = (VgaCrtcRegisters[VGA_CRTC_PRESET_ROW_SCAN_REG] >> 5) & 3;
1256 DWORD Address = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG],
1257 VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG])
1258 + PresetRowScan * ScanlineSize
1259 + BytePanning;
1260 WORD LineCompare = VgaCrtcRegisters[VGA_CRTC_LINE_COMPARE_REG]
1261 | ((VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_LC8) << 4);
1262 BYTE PixelShift = VgaAcRegisters[VGA_AC_HORZ_PANNING_REG] & 0x0F;
1263
1264 /*
1265 * If the console framebuffer is NULL, that means something
1266 * went wrong earlier and this is the final display refresh.
1267 */
1268 if (ConsoleFramebuffer == NULL) return;
1269
1270 /* Check if we are in text or graphics mode */
1271 if (ScreenMode == GRAPHICS_MODE)
1272 {
1273 /* Graphics mode */
1274 PBYTE GraphicsBuffer = (PBYTE)ConsoleFramebuffer;
1275 DWORD InterlaceHighBit = VGA_INTERLACE_HIGH_BIT;
1276 SHORT X;
1277
1278 /*
1279 * Synchronize access to the graphics framebuffer
1280 * with the console framebuffer mutex.
1281 */
1282 WaitForSingleObject(ConsoleMutex, INFINITE);
1283
1284 /* Shift the high bit right by 1 in odd/even mode */
1285 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1286 {
1287 InterlaceHighBit >>= 1;
1288 }
1289
1290 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
1291 {
1292 /* Halve the line compare value */
1293 LineCompare >>= 1;
1294 }
1295 else
1296 {
1297 /* Divide the line compare value by the maximum scan line */
1298 LineCompare /= 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1299 }
1300
1301 /* Loop through the scanlines */
1302 for (i = 0; i < CurrResolution.Y; i++)
1303 {
1304 if (i == LineCompare)
1305 {
1306 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_PPM)
1307 {
1308 /*
1309 * Disable the pixel shift count and byte panning
1310 * for the rest of the display cycle
1311 */
1312 PixelShift = 0;
1313 BytePanning = 0;
1314 }
1315
1316 /* Reset the address, but assume the preset row scan is 0 */
1317 Address = BytePanning;
1318 }
1319
1320 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
1321 {
1322 /* Odd-numbered line in interlaced mode - set the high bit */
1323 Address |= InterlaceHighBit;
1324 }
1325
1326 /* Loop through the pixels */
1327 for (j = 0; j < CurrResolution.X; j++)
1328 {
1329 BYTE PixelData = 0;
1330
1331 /* Apply horizontal pixel panning */
1332 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1333 {
1334 X = j + (PixelShift >> 1);
1335 }
1336 else
1337 {
1338 X = j + PixelShift;
1339 }
1340
1341 /* Check the shifting mode */
1342 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256)
1343 {
1344 /* 4 bits shifted from each plane */
1345
1346 /* Check if this is 16 or 256 color mode */
1347 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1348 {
1349 /* One byte per pixel */
1350 PixelData = VgaMemory[(X % VGA_NUM_BANKS) * VGA_BANK_SIZE
1351 + LOWORD((Address + (X / VGA_NUM_BANKS))
1352 * AddressSize)];
1353 }
1354 else
1355 {
1356 /* 4-bits per pixel */
1357
1358 PixelData = VgaMemory[(X % VGA_NUM_BANKS) * VGA_BANK_SIZE
1359 + LOWORD((Address + (X / (VGA_NUM_BANKS * 2)))
1360 * AddressSize)];
1361
1362 /* Check if we should use the highest 4 bits or lowest 4 */
1363 if (((X / VGA_NUM_BANKS) % 2) == 0)
1364 {
1365 /* Highest 4 */
1366 PixelData >>= 4;
1367 }
1368 else
1369 {
1370 /* Lowest 4 */
1371 PixelData &= 0x0F;
1372 }
1373 }
1374 }
1375 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG)
1376 {
1377 /* Check if this is 16 or 256 color mode */
1378 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1379 {
1380 // TODO: NOT IMPLEMENTED
1381 DPRINT1("8-bit interleaved mode is not implemented!\n");
1382 }
1383 else
1384 {
1385 /*
1386 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1387 * then 2 bits shifted from plane 1 and 3 for the next 4
1388 */
1389 DWORD BankNumber = (X / 4) % 2;
1390 DWORD Offset = Address + (X / 8);
1391 BYTE LowPlaneData = VgaMemory[BankNumber * VGA_BANK_SIZE + LOWORD(Offset * AddressSize)];
1392 BYTE HighPlaneData = VgaMemory[(BankNumber + 2) * VGA_BANK_SIZE + LOWORD(Offset * AddressSize)];
1393
1394 /* Extract the two bits from each plane */
1395 LowPlaneData = (LowPlaneData >> (6 - ((X % 4) * 2))) & 0x03;
1396 HighPlaneData = (HighPlaneData >> (6 - ((X % 4) * 2))) & 0x03;
1397
1398 /* Combine them into the pixel */
1399 PixelData = LowPlaneData | (HighPlaneData << 2);
1400 }
1401 }
1402 else
1403 {
1404 /* 1 bit shifted from each plane */
1405
1406 /* Check if this is 16 or 256 color mode */
1407 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1408 {
1409 /* 8 bits per pixel, 2 on each plane */
1410
1411 for (k = 0; k < VGA_NUM_BANKS; k++)
1412 {
1413 /* The data is on plane k, 4 pixels per byte */
1414 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
1415 + LOWORD((Address + (X / VGA_NUM_BANKS))
1416 * AddressSize)];
1417
1418 /* The mask of the first bit in the pair */
1419 BYTE BitMask = 1 << (((3 - (X % VGA_NUM_BANKS)) * 2) + 1);
1420
1421 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1422 if (PlaneData & BitMask) PixelData |= 1 << k;
1423
1424 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1425 if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4);
1426 }
1427 }
1428 else
1429 {
1430 /* 4 bits per pixel, 1 on each plane */
1431
1432 for (k = 0; k < VGA_NUM_BANKS; k++)
1433 {
1434 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
1435 + LOWORD((Address + (X / (VGA_NUM_BANKS * 2)))
1436 * AddressSize)];
1437
1438 /* If the bit on that plane is set, set it */
1439 if (PlaneData & (1 << (7 - (X % 8)))) PixelData |= 1 << k;
1440 }
1441 }
1442 }
1443
1444 if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT))
1445 {
1446 /*
1447 * In 16 color mode, the value is an index to the AC registers
1448 * if external palette access is disabled, otherwise (in case
1449 * of palette loading) it is a blank pixel.
1450 */
1451 PixelData = (VgaAcPalDisable ? VgaAcRegisters[PixelData & 0x0F]
1452 : 0);
1453 }
1454
1455 /* Take into account DoubleVision mode when checking for pixel updates */
1456 if (DoubleWidth && DoubleHeight)
1457 {
1458 /* Now check if the resulting pixel data has changed */
1459 if (GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2)] != PixelData)
1460 {
1461 /* Yes, write the new value */
1462 GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2)] = PixelData;
1463 GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2 + 1)] = PixelData;
1464 GraphicsBuffer[((i * 2 + 1) * CurrResolution.X * 2) + (j * 2)] = PixelData;
1465 GraphicsBuffer[((i * 2 + 1) * CurrResolution.X * 2) + (j * 2 + 1)] = PixelData;
1466
1467 /* Mark the specified pixel as changed */
1468 VgaMarkForUpdate(i, j);
1469 }
1470 }
1471 else if (DoubleWidth && !DoubleHeight)
1472 {
1473 /* Now check if the resulting pixel data has changed */
1474 if (GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2)] != PixelData)
1475 {
1476 /* Yes, write the new value */
1477 GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2)] = PixelData;
1478 GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2 + 1)] = PixelData;
1479
1480 /* Mark the specified pixel as changed */
1481 VgaMarkForUpdate(i, j);
1482 }
1483 }
1484 else if (!DoubleWidth && DoubleHeight)
1485 {
1486 /* Now check if the resulting pixel data has changed */
1487 if (GraphicsBuffer[(i * 2 * CurrResolution.X) + j] != PixelData)
1488 {
1489 /* Yes, write the new value */
1490 GraphicsBuffer[(i * 2 * CurrResolution.X) + j] = PixelData;
1491 GraphicsBuffer[((i * 2 + 1) * CurrResolution.X) + j] = PixelData;
1492
1493 /* Mark the specified pixel as changed */
1494 VgaMarkForUpdate(i, j);
1495 }
1496 }
1497 else // if (!DoubleWidth && !DoubleHeight)
1498 {
1499 /* Now check if the resulting pixel data has changed */
1500 if (GraphicsBuffer[i * CurrResolution.X + j] != PixelData)
1501 {
1502 /* Yes, write the new value */
1503 GraphicsBuffer[i * CurrResolution.X + j] = PixelData;
1504
1505 /* Mark the specified pixel as changed */
1506 VgaMarkForUpdate(i, j);
1507 }
1508 }
1509 }
1510
1511 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
1512 {
1513 /* Clear the high bit */
1514 Address &= ~InterlaceHighBit;
1515 }
1516
1517 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) || (i & 1))
1518 {
1519 /* Move to the next scanline */
1520 Address += ScanlineSize;
1521 }
1522 }
1523
1524 /*
1525 * Release the console framebuffer mutex
1526 * so that we allow for repainting.
1527 */
1528 ReleaseMutex(ConsoleMutex);
1529 }
1530 else
1531 {
1532 /* Text mode */
1533 DWORD CurrentAddr;
1534 PCHAR_CELL CharBuffer = (PCHAR_CELL)ConsoleFramebuffer;
1535 CHAR_CELL CharInfo;
1536
1537 /*
1538 * Technically, the horizontal panning and preset row count should
1539 * affect text mode too. However, it works on pixels and not characters,
1540 * so we can't support it currently.
1541 */
1542
1543 /* Loop through the scanlines */
1544 for (i = 0; i < CurrResolution.Y; i++)
1545 {
1546 /* Loop through the characters */
1547 for (j = 0; j < CurrResolution.X; j++)
1548 {
1549 CurrentAddr = LOWORD((Address + j) * AddressSize);
1550
1551 /* Plane 0 holds the character itself */
1552 CharInfo.Char = VgaMemory[CurrentAddr];
1553
1554 /* Plane 1 holds the attribute */
1555 CharInfo.Attributes = VgaMemory[CurrentAddr + VGA_BANK_SIZE];
1556
1557 /* Now check if the resulting character data has changed */
1558 if ((CharBuffer[i * CurrResolution.X + j].Char != CharInfo.Char) ||
1559 (CharBuffer[i * CurrResolution.X + j].Attributes != CharInfo.Attributes))
1560 {
1561 /* Yes, write the new value */
1562 CharBuffer[i * CurrResolution.X + j] = CharInfo;
1563
1564 /* Mark the specified cell as changed */
1565 VgaMarkForUpdate(i, j);
1566 }
1567 }
1568
1569 /* Move to the next scanline */
1570 Address += ScanlineSize;
1571 }
1572 }
1573 }
1574
1575 static VOID VgaUpdateTextCursor(VOID)
1576 {
1577 COORD Position;
1578 CONSOLE_CURSOR_INFO CursorInfo;
1579
1580 BOOL CursorVisible = !(VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x20);
1581 BYTE CursorStart = VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x1F;
1582 BYTE CursorEnd = VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] & 0x1F;
1583
1584 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1585 BYTE TextSize = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1586 WORD Location = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG],
1587 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG]);
1588
1589 /* Just return if we are not in text mode */
1590 if (ScreenMode != TEXT_MODE) return;
1591
1592 if (CursorStart < CursorEnd)
1593 {
1594 /* Visible cursor */
1595 CursorInfo.bVisible = CursorVisible;
1596 CursorInfo.dwSize = (100 * (CursorEnd - CursorStart)) / TextSize;
1597 }
1598 else
1599 {
1600 /* Hidden cursor */
1601 CursorInfo.bVisible = FALSE;
1602 CursorInfo.dwSize = 1; // The size needs to be non-zero for SetConsoleCursorInfo to succeed.
1603 }
1604
1605 /* Add the cursor skew to the location */
1606 Location += (VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] >> 5) & 0x03;
1607
1608 /* Find the coordinates of the new position */
1609 Position.X = (SHORT)(Location % ScanlineSize);
1610 Position.Y = (SHORT)(Location / ScanlineSize);
1611
1612 DPRINT("VgaUpdateTextCursor: (X = %d ; Y = %d)\n", Position.X, Position.Y);
1613
1614 /* Update the physical cursor */
1615 SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
1616 SetConsoleCursorPosition(TextConsoleBuffer, Position);
1617
1618 /* Reset the cursor changed flag */
1619 CursorChanged = FALSE;
1620 }
1621
1622 static BYTE WINAPI VgaReadPort(USHORT Port)
1623 {
1624 DPRINT("VgaReadPort: Port 0x%X\n", Port);
1625
1626 if (Port != VGA_DAC_MASK) SvgaHdrCounter = 0;
1627
1628 switch (Port)
1629 {
1630 case VGA_MISC_READ:
1631 return VgaMiscRegister;
1632
1633 case VGA_INSTAT0_READ:
1634 return 0; // Not implemented
1635
1636 case VGA_INSTAT1_READ_MONO:
1637 case VGA_INSTAT1_READ_COLOR:
1638 {
1639 BYTE Result = 0;
1640 BOOLEAN Vsync, Hsync;
1641 ULONGLONG Cycles = GetCycleCount();
1642 ULONG CyclesPerMicrosecond = (ULONG)((GetCycleSpeed() + 500000ULL) / 1000000ULL);
1643 ULONG Dots = (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & 1) ? 9 : 8;
1644 ULONG Clock = VgaGetClockFrequency() / 1000000;
1645 ULONG HorizTotalDots = ((ULONG)VgaCrtcRegisters[VGA_CRTC_HORZ_TOTAL_REG] + 5) * Dots;
1646 ULONG VblankStart, VblankEnd, HblankStart, HblankEnd;
1647 ULONG HblankDuration, VblankDuration;
1648
1649 /* Calculate the vertical blanking duration in cycles */
1650 VblankStart = VgaCrtcRegisters[VGA_CRTC_START_VERT_BLANKING_REG] & 0x7F;
1651 VblankEnd = VgaCrtcRegisters[VGA_CRTC_END_VERT_BLANKING_REG] & 0x7F;
1652 if (VblankEnd < VblankStart) VblankEnd |= 0x80;
1653 VblankDuration = ((VblankEnd - VblankStart) * HorizTotalDots
1654 * CyclesPerMicrosecond + (Clock >> 1)) / Clock;
1655
1656 /* Calculate the horizontal blanking duration in cycles */
1657 HblankStart = VgaCrtcRegisters[VGA_CRTC_START_HORZ_BLANKING_REG] & 0x1F;
1658 HblankEnd = VgaCrtcRegisters[VGA_CRTC_END_HORZ_BLANKING_REG] & 0x1F;
1659 if (HblankEnd < HblankStart) HblankEnd |= 0x20;
1660 HblankDuration = ((HblankEnd - HblankStart) * Dots
1661 * CyclesPerMicrosecond + (Clock >> 1)) / Clock;
1662
1663 Vsync = (Cycles - VerticalRetraceCycle) < (ULONGLONG)VblankDuration;
1664 Hsync = (Cycles - HorizontalRetraceCycle) < (ULONGLONG)HblankDuration;
1665
1666 /* Reset the AC latch */
1667 VgaAcLatch = FALSE;
1668
1669 /* Reverse the polarity, if needed */
1670 if (VgaMiscRegister & VGA_MISC_VSYNCP) Vsync = !Vsync;
1671 if (VgaMiscRegister & VGA_MISC_HSYNCP) Hsync = !Hsync;
1672
1673 /* Set a flag if there is a vertical or horizontal retrace */
1674 if (Vsync || Hsync) Result |= VGA_STAT_DD;
1675
1676 /* Set an additional flag if there was a vertical retrace */
1677 if (Vsync) Result |= VGA_STAT_VRETRACE;
1678
1679 return Result;
1680 }
1681
1682 case VGA_FEATURE_READ:
1683 return VgaFeatureRegister;
1684
1685 case VGA_AC_INDEX:
1686 return VgaAcIndex;
1687
1688 case VGA_AC_READ:
1689 return VgaAcRegisters[VgaAcIndex];
1690
1691 case VGA_SEQ_INDEX:
1692 return VgaSeqIndex;
1693
1694 case VGA_SEQ_DATA:
1695 return VgaSeqRegisters[VgaSeqIndex];
1696
1697 case VGA_DAC_MASK:
1698 {
1699 if (SvgaHdrCounter == 4)
1700 {
1701 SvgaHdrCounter = 0;
1702 return SvgaHiddenRegister;
1703 }
1704 else
1705 {
1706 SvgaHdrCounter++;
1707 return VgaDacMask;
1708 }
1709 }
1710
1711 case VGA_DAC_READ_INDEX:
1712 /* This returns the read/write state */
1713 return (VgaDacReadWrite ? 0 : 3);
1714
1715 case VGA_DAC_WRITE_INDEX:
1716 return VgaDacIndex;
1717
1718 case VGA_DAC_DATA:
1719 {
1720 /* Ignore reads in write mode */
1721 if (!VgaDacReadWrite)
1722 {
1723 BYTE Data = VgaDacRegisters[VgaDacIndex * 3 + VgaDacLatchCounter];
1724 VgaDacLatchCounter++;
1725
1726 if (VgaDacLatchCounter == 3)
1727 {
1728 /* Reset the latch counter and increment the palette index */
1729 VgaDacLatchCounter = 0;
1730 VgaDacIndex++;
1731 VgaDacIndex %= VGA_MAX_COLORS;
1732 }
1733
1734 return Data;
1735 }
1736
1737 break;
1738 }
1739
1740 case VGA_CRTC_INDEX_MONO:
1741 case VGA_CRTC_INDEX_COLOR:
1742 return VgaCrtcIndex;
1743
1744 case VGA_CRTC_DATA_MONO:
1745 case VGA_CRTC_DATA_COLOR:
1746 return VgaCrtcRegisters[VgaCrtcIndex];
1747
1748 case VGA_GC_INDEX:
1749 return VgaGcIndex;
1750
1751 case VGA_GC_DATA:
1752 return VgaGcRegisters[VgaGcIndex];
1753
1754 default:
1755 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port);
1756 break;
1757 }
1758
1759 return 0;
1760 }
1761
1762 static inline VOID VgaWriteSequencer(BYTE Data)
1763 {
1764 /* Save the value */
1765 VgaSeqRegisters[VgaSeqIndex & VGA_SEQ_INDEX_MASK] = Data;
1766
1767 /* Check the index */
1768 switch (VgaSeqIndex & VGA_SEQ_INDEX_MASK)
1769 {
1770 case SVGA_SEQ_UNLOCK_REG:
1771 {
1772 if ((Data & SVGA_SEQ_UNLOCK_MASK) == SVGA_SEQ_UNLOCKED)
1773 {
1774 /* Unlock SVGA extensions */
1775 VgaSeqRegisters[SVGA_SEQ_UNLOCK_REG] = SVGA_SEQ_UNLOCKED;
1776 }
1777 else
1778 {
1779 /* Lock SVGA extensions */
1780 VgaSeqRegisters[SVGA_SEQ_UNLOCK_REG] = SVGA_SEQ_LOCKED;
1781 }
1782
1783 break;
1784 }
1785 }
1786 }
1787
1788 static inline VOID VgaWriteGc(BYTE Data)
1789 {
1790 /* Save the value */
1791 VgaGcRegisters[VgaGcIndex & VGA_GC_INDEX_MASK] = Data;
1792
1793 /* Check the index */
1794 switch (VgaGcIndex & VGA_GC_INDEX_MASK)
1795 {
1796 case VGA_GC_MISC_REG:
1797 {
1798 /* Remove any existing VGA memory hook */
1799 MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
1800
1801 if (VgaMiscRegister & VGA_MISC_RAM_ENABLED)
1802 {
1803 UCHAR MemoryMap = (VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03;
1804
1805 /* Register a memory hook */
1806 MemInstallFastMemoryHook((PVOID)MemoryBase[MemoryMap],
1807 MemorySize[MemoryMap],
1808 VgaReadMemory,
1809 VgaWriteMemory);
1810 }
1811
1812 /* The GC misc register decides if it's text or graphics mode */
1813 ModeChanged = TRUE;
1814 break;
1815 }
1816 }
1817 }
1818
1819 static inline VOID VgaWriteCrtc(BYTE Data)
1820 {
1821 /* Save the value */
1822 VgaCrtcRegisters[VgaCrtcIndex & VGA_CRTC_INDEX_MASK] = Data;
1823
1824 /* Check the index */
1825 switch (VgaCrtcIndex & VGA_CRTC_INDEX_MASK)
1826 {
1827 case VGA_CRTC_END_HORZ_DISP_REG:
1828 case VGA_CRTC_VERT_DISP_END_REG:
1829 case VGA_CRTC_OVERFLOW_REG:
1830 case VGA_CRTC_MAX_SCAN_LINE_REG:
1831 {
1832 /* The video mode has changed */
1833 ModeChanged = TRUE;
1834 break;
1835 }
1836
1837 case VGA_CRTC_CURSOR_LOC_LOW_REG:
1838 case VGA_CRTC_CURSOR_LOC_HIGH_REG:
1839 case VGA_CRTC_CURSOR_START_REG:
1840 case VGA_CRTC_CURSOR_END_REG:
1841 {
1842 /* Set the cursor changed flag */
1843 CursorChanged = TRUE;
1844 break;
1845 }
1846 }
1847 }
1848
1849 static inline VOID VgaWriteDac(BYTE Data)
1850 {
1851 UINT i;
1852 PALETTEENTRY Entry;
1853
1854 /* Store the value in the latch */
1855 VgaDacLatch[VgaDacLatchCounter++] = Data;
1856 if (VgaDacLatchCounter < 3) return;
1857
1858 /* Reset the latch counter */
1859 VgaDacLatchCounter = 0;
1860
1861 /* Set the DAC register values */
1862 VgaDacRegisters[VgaDacIndex * 3] = VgaDacLatch[0];
1863 VgaDacRegisters[VgaDacIndex * 3 + 1] = VgaDacLatch[1];
1864 VgaDacRegisters[VgaDacIndex * 3 + 2] = VgaDacLatch[2];
1865
1866 /* Fill the entry structure */
1867 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacLatch[0]);
1868 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacLatch[1]);
1869 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacLatch[2]);
1870 Entry.peFlags = 0;
1871
1872 /* Update the palette entry */
1873 SetPaletteEntries(PaletteHandle, VgaDacIndex, 1, &Entry);
1874
1875 /* Check which text palette entries are affected */
1876 for (i = 0; i <= VGA_AC_PAL_F_REG; i++)
1877 {
1878 if (VgaAcRegisters[i] == VgaDacIndex)
1879 {
1880 /* Update the text palette entry */
1881 SetPaletteEntries(TextPaletteHandle, i, 1, &Entry);
1882 }
1883 }
1884
1885 /* Set the palette changed flag */
1886 PaletteChanged = TRUE;
1887
1888 /* Update the index */
1889 VgaDacIndex++;
1890 VgaDacIndex %= VGA_MAX_COLORS;
1891 }
1892
1893 static inline VOID VgaWriteAc(BYTE Data)
1894 {
1895 PALETTEENTRY Entry;
1896
1897 ASSERT(VgaAcIndex < VGA_AC_MAX_REG);
1898
1899 /* Save the value */
1900 if (VgaAcIndex <= VGA_AC_PAL_F_REG)
1901 {
1902 if (VgaAcPalDisable) return;
1903
1904 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
1905 if (VgaAcRegisters[VgaAcIndex] != Data)
1906 {
1907 /* Update the AC register */
1908 VgaAcRegisters[VgaAcIndex] = Data;
1909
1910 /* Fill the entry structure */
1911 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3]);
1912 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3 + 1]);
1913 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3 + 2]);
1914 Entry.peFlags = 0;
1915
1916 /* Update the palette entry and set the palette change flag */
1917 SetPaletteEntries(TextPaletteHandle, VgaAcIndex, 1, &Entry);
1918 PaletteChanged = TRUE;
1919 }
1920 }
1921 else
1922 {
1923 VgaAcRegisters[VgaAcIndex] = Data;
1924 }
1925 }
1926
1927 static VOID WINAPI VgaWritePort(USHORT Port, BYTE Data)
1928 {
1929 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port, Data);
1930
1931 switch (Port)
1932 {
1933 case VGA_MISC_WRITE:
1934 {
1935 VgaMiscRegister = Data;
1936
1937 if (VgaMiscRegister & 0x01)
1938 {
1939 /* Color emulation */
1940 DPRINT1("Color emulation\n");
1941
1942 /* Register the new I/O Ports */
1943 RegisterIoPort(0x3D4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_COLOR
1944 RegisterIoPort(0x3D5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_COLOR
1945 RegisterIoPort(0x3DA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1946
1947 /* Unregister the old ones */
1948 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1949 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1950 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1951 }
1952 else
1953 {
1954 /* Monochrome emulation */
1955 DPRINT1("Monochrome emulation\n");
1956
1957 /* Register the new I/O Ports */
1958 RegisterIoPort(0x3B4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_MONO
1959 RegisterIoPort(0x3B5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_MONO
1960 RegisterIoPort(0x3BA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1961
1962 /* Unregister the old ones */
1963 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1964 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1965 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1966 }
1967
1968 /* Remove any existing VGA memory hook */
1969 MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
1970
1971 if (VgaMiscRegister & VGA_MISC_RAM_ENABLED)
1972 {
1973 UCHAR MemoryMap = (VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03;
1974
1975 /* Register a memory hook */
1976 MemInstallFastMemoryHook((PVOID)MemoryBase[MemoryMap],
1977 MemorySize[MemoryMap],
1978 VgaReadMemory,
1979 VgaWriteMemory);
1980 }
1981
1982 break;
1983 }
1984
1985 case VGA_FEATURE_WRITE_MONO:
1986 case VGA_FEATURE_WRITE_COLOR:
1987 {
1988 VgaFeatureRegister = Data;
1989 break;
1990 }
1991
1992 case VGA_AC_INDEX:
1993 // case VGA_AC_WRITE:
1994 {
1995 if (!VgaAcLatch)
1996 {
1997 /* Change the index */
1998 BYTE Index = Data & 0x1F;
1999 if (Index < VGA_AC_MAX_REG) VgaAcIndex = Index;
2000
2001 /*
2002 * Change palette protection by checking for
2003 * the Palette Address Source bit.
2004 */
2005 VgaAcPalDisable = (Data & 0x20) ? TRUE : FALSE;
2006 }
2007 else
2008 {
2009 /* Write the data */
2010 VgaWriteAc(Data);
2011 }
2012
2013 /* Toggle the latch */
2014 VgaAcLatch = !VgaAcLatch;
2015 break;
2016 }
2017
2018 case VGA_SEQ_INDEX:
2019 {
2020 /* Set the sequencer index register */
2021 if ((Data & 0x1F) < SVGA_SEQ_MAX_UNLOCKED_REG
2022 && (Data & 0x1F) != VGA_SEQ_MAX_REG)
2023 {
2024 VgaSeqIndex = Data;
2025 }
2026
2027 break;
2028 }
2029
2030 case VGA_SEQ_DATA:
2031 {
2032 /* Call the sequencer function */
2033 VgaWriteSequencer(Data);
2034 break;
2035 }
2036
2037 case VGA_DAC_MASK:
2038 {
2039 if (SvgaHdrCounter == 4) SvgaHiddenRegister = Data;
2040 else VgaDacMask = Data;
2041
2042 break;
2043 }
2044
2045 case VGA_DAC_READ_INDEX:
2046 {
2047 VgaDacReadWrite = FALSE;
2048 VgaDacIndex = Data;
2049 VgaDacLatchCounter = 0;
2050 break;
2051 }
2052
2053 case VGA_DAC_WRITE_INDEX:
2054 {
2055 VgaDacReadWrite = TRUE;
2056 VgaDacIndex = Data;
2057 VgaDacLatchCounter = 0;
2058 break;
2059 }
2060
2061 case VGA_DAC_DATA:
2062 {
2063 /* Ignore writes in read mode */
2064 if (VgaDacReadWrite) VgaWriteDac(Data & 0x3F);
2065 break;
2066 }
2067
2068 case VGA_CRTC_INDEX_MONO:
2069 case VGA_CRTC_INDEX_COLOR:
2070 {
2071 /* Set the CRTC index register */
2072 if (((Data & VGA_CRTC_INDEX_MASK) < SVGA_CRTC_MAX_UNLOCKED_REG)
2073 && ((Data & VGA_CRTC_INDEX_MASK) < SVGA_CRTC_UNUSED0_REG
2074 || (Data & VGA_CRTC_INDEX_MASK) > SVGA_CRTC_UNUSED6_REG)
2075 && (Data & VGA_CRTC_INDEX_MASK) != SVGA_CRTC_UNUSED7_REG)
2076 {
2077 VgaCrtcIndex = Data;
2078 }
2079
2080 break;
2081 }
2082
2083 case VGA_CRTC_DATA_MONO:
2084 case VGA_CRTC_DATA_COLOR:
2085 {
2086 /* Call the CRTC function */
2087 VgaWriteCrtc(Data);
2088 break;
2089 }
2090
2091 case VGA_GC_INDEX:
2092 {
2093 /* Set the GC index register */
2094 if ((Data & VGA_GC_INDEX_MASK) < SVGA_GC_MAX_UNLOCKED_REG
2095 && (Data & VGA_GC_INDEX_MASK) != SVGA_GC_UNUSED0_REG
2096 && ((Data & VGA_GC_INDEX_MASK) < SVGA_GC_UNUSED1_REG
2097 || (Data & VGA_GC_INDEX_MASK) > SVGA_GC_UNUSED10_REG))
2098 {
2099 VgaGcIndex = Data;
2100 }
2101
2102 break;
2103 }
2104
2105 case VGA_GC_DATA:
2106 {
2107 /* Call the GC function */
2108 VgaWriteGc(Data);
2109 break;
2110 }
2111
2112 default:
2113 DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port, Data);
2114 break;
2115 }
2116
2117 SvgaHdrCounter = 0;
2118 }
2119
2120 static VOID FASTCALL VgaVerticalRetrace(ULONGLONG ElapsedTime)
2121 {
2122 HANDLE ConsoleBufferHandle = NULL;
2123
2124 UNREFERENCED_PARAMETER(ElapsedTime);
2125
2126 /* Set the vertical retrace cycle */
2127 VerticalRetraceCycle = GetCycleCount();
2128
2129 /* If nothing has changed, just return */
2130 // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
2131 // return;
2132
2133 /* Change the display mode */
2134 if (ModeChanged) VgaChangeMode();
2135
2136 /* Change the text cursor appearance */
2137 if (CursorChanged) VgaUpdateTextCursor();
2138
2139 if (PaletteChanged)
2140 {
2141 /* Trigger a full update of the screen */
2142 NeedsUpdate = TRUE;
2143 UpdateRectangle.Left = 0;
2144 UpdateRectangle.Top = 0;
2145 UpdateRectangle.Right = CurrResolution.X;
2146 UpdateRectangle.Bottom = CurrResolution.Y;
2147
2148 PaletteChanged = FALSE;
2149 }
2150
2151 /* Update the contents of the framebuffer */
2152 VgaUpdateFramebuffer();
2153
2154 /* Ignore if there's nothing to update */
2155 if (!NeedsUpdate) return;
2156
2157 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
2158 UpdateRectangle.Left,
2159 UpdateRectangle.Top,
2160 UpdateRectangle.Right,
2161 UpdateRectangle.Bottom);
2162
2163 /* Check if we are in text or graphics mode */
2164 if (ScreenMode == GRAPHICS_MODE)
2165 {
2166 /* Graphics mode */
2167 ConsoleBufferHandle = GraphicsConsoleBuffer;
2168
2169 /* In DoubleVision mode, scale the update rectangle */
2170 if (DoubleWidth)
2171 {
2172 UpdateRectangle.Left *= 2;
2173 UpdateRectangle.Right = UpdateRectangle.Right * 2 + 1;
2174 }
2175 if (DoubleHeight)
2176 {
2177 UpdateRectangle.Top *= 2;
2178 UpdateRectangle.Bottom = UpdateRectangle.Bottom * 2 + 1;
2179 }
2180 }
2181 else
2182 {
2183 /* Text mode */
2184 ConsoleBufferHandle = TextConsoleBuffer;
2185 }
2186
2187 /* Redraw the screen */
2188 __InvalidateConsoleDIBits(ConsoleBufferHandle, &UpdateRectangle);
2189
2190 /* Clear the update flag */
2191 NeedsUpdate = FALSE;
2192 }
2193
2194 static VOID FASTCALL VgaHorizontalRetrace(ULONGLONG ElapsedTime)
2195 {
2196 UNREFERENCED_PARAMETER(ElapsedTime);
2197
2198 /* Set the cycle */
2199 HorizontalRetraceCycle = GetCycleCount();
2200 }
2201
2202 /* PUBLIC FUNCTIONS ***********************************************************/
2203
2204 COORD VgaGetDisplayResolution(VOID)
2205 {
2206 COORD Resolution;
2207 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
2208
2209 /* The low 8 bits are in the display registers */
2210 Resolution.X = VgaCrtcRegisters[VGA_CRTC_END_HORZ_DISP_REG];
2211 Resolution.Y = VgaCrtcRegisters[VGA_CRTC_VERT_DISP_END_REG];
2212
2213 /* Set the top bits from the overflow register */
2214 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
2215 {
2216 Resolution.Y |= 1 << 8;
2217 }
2218 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
2219 {
2220 Resolution.Y |= 1 << 9;
2221 }
2222
2223 /* Increase the values by 1 */
2224 Resolution.X++;
2225 Resolution.Y++;
2226
2227 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
2228 {
2229 /* Multiply the horizontal resolution by the 9/8 dot mode */
2230 Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
2231 ? 8 : 9;
2232
2233 /* The horizontal resolution is halved in 8-bit mode */
2234 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
2235 }
2236
2237 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
2238 {
2239 /* Halve the vertical resolution */
2240 Resolution.Y >>= 1;
2241 }
2242 else
2243 {
2244 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
2245 Resolution.Y /= MaximumScanLine;
2246 }
2247
2248 /* Return the resolution */
2249 return Resolution;
2250 }
2251
2252 BOOLEAN VgaGetDoubleVisionState(PBOOLEAN Horizontal, PBOOLEAN Vertical)
2253 {
2254 if (GraphicsConsoleBuffer == NULL) return FALSE;
2255 if (Horizontal) *Horizontal = DoubleWidth;
2256 if (Vertical) *Vertical = DoubleHeight;
2257 return TRUE;
2258 }
2259
2260 VOID VgaRefreshDisplay(VOID)
2261 {
2262 VgaVerticalRetrace(0);
2263 }
2264
2265 VOID FASTCALL VgaReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
2266 {
2267 DWORD i, j;
2268 DWORD VideoAddress;
2269 PUCHAR BufPtr = (PUCHAR)Buffer;
2270
2271 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
2272
2273 /* Ignore if video RAM access is disabled */
2274 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
2275
2276 if (!(VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_READ))
2277 {
2278 /* Loop through each byte */
2279 for (i = 0; i < Size; i++)
2280 {
2281 VideoAddress = VgaTranslateReadAddress(Address + i);
2282
2283 /* Copy the value to the buffer */
2284 BufPtr[i] = VgaMemory[VideoAddress];
2285 }
2286 }
2287 else
2288 {
2289 /* Loop through each byte */
2290 for (i = 0; i < Size; i++)
2291 {
2292 BYTE Result = 0xFF;
2293
2294 /* This should always return a plane 0 address for read mode 1 */
2295 VideoAddress = VgaTranslateReadAddress(Address + i);
2296
2297 for (j = 0; j < VGA_NUM_BANKS; j++)
2298 {
2299 /* Don't consider ignored banks */
2300 if (!(VgaGcRegisters[VGA_GC_COLOR_IGNORE_REG] & (1 << j))) continue;
2301
2302 if (VgaGcRegisters[VGA_GC_COLOR_COMPARE_REG] & (1 << j))
2303 {
2304 /* Comparing with 11111111 */
2305 Result &= VgaMemory[j * VGA_BANK_SIZE + LOWORD(VideoAddress)];
2306 }
2307 else
2308 {
2309 /* Comparing with 00000000 */
2310 Result &= ~(VgaMemory[j * VGA_BANK_SIZE + LOWORD(VideoAddress)]);
2311 }
2312 }
2313
2314 /* Copy the value to the buffer */
2315 BufPtr[i] = Result;
2316 }
2317 }
2318
2319 /* Load the latch registers */
2320 VgaLatchRegisters[0] = VgaMemory[LOWORD(VideoAddress)];
2321 VgaLatchRegisters[1] = VgaMemory[VGA_BANK_SIZE + LOWORD(VideoAddress)];
2322 VgaLatchRegisters[2] = VgaMemory[(2 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
2323 VgaLatchRegisters[3] = VgaMemory[(3 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
2324 }
2325
2326 BOOLEAN FASTCALL VgaWriteMemory(ULONG Address, PVOID Buffer, ULONG Size)
2327 {
2328 DWORD i, j;
2329 DWORD VideoAddress;
2330 PUCHAR BufPtr = (PUCHAR)Buffer;
2331
2332 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
2333
2334 /* Ignore if video RAM access is disabled */
2335 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return TRUE;
2336
2337 /* Also ignore if write access to all planes is disabled */
2338 if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return TRUE;
2339
2340 /* Loop through each byte */
2341 for (i = 0; i < Size; i++)
2342 {
2343 VideoAddress = VgaTranslateWriteAddress(Address + i);
2344
2345 for (j = 0; j < VGA_NUM_BANKS; j++)
2346 {
2347 /* Make sure the page is writeable */
2348 if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue;
2349
2350 /* Check if this is chain-4 mode */
2351 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
2352 {
2353 if (((Address + i) & 0x03) != j)
2354 {
2355 /* This plane will not be accessed */
2356 continue;
2357 }
2358 }
2359
2360 /* Check if this is odd-even mode */
2361 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
2362 {
2363 if (((Address + i) & 0x01) != (j & 1))
2364 {
2365 /* This plane will not be accessed */
2366 continue;
2367 }
2368 }
2369
2370 /* Copy the value to the VGA memory */
2371 VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(BufPtr[i], j);
2372 }
2373 }
2374
2375 return TRUE;
2376 }
2377
2378 VOID VgaClearMemory(VOID)
2379 {
2380 RtlZeroMemory(VgaMemory, sizeof(VgaMemory));
2381 }
2382
2383 VOID VgaWriteTextModeFont(UINT FontNumber, CONST UCHAR* FontData, UINT Height)
2384 {
2385 UINT i, j;
2386 PUCHAR FontMemory = (PUCHAR)&VgaMemory[VGA_BANK_SIZE * VGA_FONT_BANK + (FontNumber * VGA_FONT_SIZE)];
2387
2388 ASSERT(Height <= VGA_MAX_FONT_HEIGHT);
2389
2390 for (i = 0 ; i < VGA_FONT_CHARACTERS; i++)
2391 {
2392 /* Write the character */
2393 for (j = 0; j < Height; j++)
2394 {
2395 FontMemory[i * VGA_MAX_FONT_HEIGHT + j] = FontData[i * Height + j];
2396 }
2397
2398 /* Clear the unused part */
2399 for (j = Height; j < VGA_MAX_FONT_HEIGHT; j++)
2400 {
2401 FontMemory[i * VGA_MAX_FONT_HEIGHT + j] = 0;
2402 }
2403 }
2404 }
2405
2406 VOID ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent)
2407 {
2408 /*
2409 * This function monitors and allows console resizings only if they are triggered by us.
2410 * User-driven resizings via the console properties, or programmatical console resizings
2411 * made by explicit calls to SetConsoleScreenBufferSize by external applications, are forbidden.
2412 * In that case only a console window resize is done in case the size is reduced.
2413 * This protection is enabled in CONSRV side when NTVDM registers as a VDM to CONSRV,
2414 * but we also implement it there in case we are running in STANDALONE mode without
2415 * CONSRV registration.
2416 *
2417 * The only potential problem we have is that, when this handler is called,
2418 * the console is already resized. In case this corresponds to a forbidden resize,
2419 * we resize the console back to its original size from inside the handler.
2420 * This will trigger a recursive call to the handler, that should be detected.
2421 */
2422
2423 if (CurrResolution.X == ScreenEvent->dwSize.X &&
2424 CurrResolution.Y == ScreenEvent->dwSize.Y)
2425 {
2426 /* Allowed resize, we are OK */
2427 return;
2428 }
2429
2430 DPRINT1("ScreenEventHandler - Detected forbidden resize! Reset console screenbuffer size back to (X = %d ; Y = %d)\n", CurrResolution.X, CurrResolution.Y);
2431
2432 // FIXME: If we're detaching, then stop monitoring for changes!!
2433
2434 /* Restore the original console size */
2435 ResizeTextConsole(&CurrResolution, NULL);
2436
2437 /* Force refresh of all the screen */
2438 NeedsUpdate = TRUE;
2439 UpdateRectangle.Left = 0;
2440 UpdateRectangle.Top = 0;
2441 UpdateRectangle.Right = CurrResolution.X;
2442 UpdateRectangle.Bottom = CurrResolution.Y;
2443 VgaRefreshDisplay();
2444 }
2445
2446 BOOL VgaAttachToConsole(VOID)
2447 {
2448 if (TextResolution.X == 0 || TextResolution.Y == 0)
2449 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
2450
2451 if (TextResolution.X == 0) TextResolution.X = 80;
2452 if (TextResolution.Y == 0) TextResolution.Y = 25;
2453
2454 // VgaDetachFromConsoleInternal();
2455
2456 /*
2457 * VgaAttachToConsoleInternal sets TextResolution
2458 * to the new resolution and updates ConsoleInfo.
2459 */
2460 if (!VgaAttachToConsoleInternal(&TextResolution))
2461 {
2462 DisplayMessage(L"An unexpected error occurred!\n");
2463 EmulatorTerminate();
2464 return FALSE;
2465 }
2466
2467 /* Restore the original screen buffer */
2468 VgaSetActiveScreenBuffer(ScreenBufferHandle);
2469 ScreenBufferHandle = NULL;
2470
2471 /* Restore the screen state */
2472 if (ScreenMode == TEXT_MODE)
2473 {
2474 /* The text mode framebuffer was recreated */
2475 ConsoleFramebuffer = TextFramebuffer;
2476 }
2477 else
2478 {
2479 /* The graphics mode framebuffer is unchanged */
2480 ConsoleFramebuffer = OldConsoleFramebuffer;
2481 }
2482 OldConsoleFramebuffer = NULL;
2483
2484 return TRUE;
2485 }
2486
2487 VOID VgaDetachFromConsole(VOID)
2488 {
2489 VgaDetachFromConsoleInternal();
2490
2491 /* Save the screen state */
2492 if (ScreenMode == TEXT_MODE)
2493 ScreenBufferHandle = TextConsoleBuffer;
2494 else
2495 ScreenBufferHandle = GraphicsConsoleBuffer;
2496
2497 /* Reset the active framebuffer */
2498 OldConsoleFramebuffer = ConsoleFramebuffer;
2499 ConsoleFramebuffer = NULL;
2500
2501 /* Restore the original console size */
2502 ResizeTextConsole(&OrgConsoleBufferInfo.dwSize, &OrgConsoleBufferInfo.srWindow);
2503
2504 /* Restore the original cursor shape */
2505 SetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo);
2506
2507 // FIXME: Should we copy back the screen data to the screen buffer??
2508 // WriteConsoleOutputA(...);
2509
2510 // FIXME: Should we change cursor POSITION??
2511 // VgaUpdateTextCursor();
2512
2513 ///* Update the physical cursor */
2514 //SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
2515 //SetConsoleCursorPosition(TextConsoleBuffer, Position /*OrgConsoleBufferInfo.dwCursorPosition*/);
2516
2517 /* Restore the old text-mode screen buffer */
2518 VgaSetActiveScreenBuffer(TextConsoleBuffer);
2519 }
2520
2521 BOOLEAN VgaInitialize(HANDLE TextHandle)
2522 {
2523 /* Save the default text-mode console output handle */
2524 if (!IsConsoleHandle(TextHandle)) return FALSE;
2525 TextConsoleBuffer = TextHandle;
2526
2527 /* Save the original cursor and console screen buffer information */
2528 if (!GetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo) ||
2529 !GetConsoleScreenBufferInfo(TextConsoleBuffer, &OrgConsoleBufferInfo))
2530 {
2531 return FALSE;
2532 }
2533 ConsoleInfo = OrgConsoleBufferInfo;
2534
2535 /* Clear the SEQ, GC, CRTC and AC registers */
2536 RtlZeroMemory(VgaSeqRegisters , sizeof(VgaSeqRegisters ));
2537 RtlZeroMemory(VgaGcRegisters , sizeof(VgaGcRegisters ));
2538 RtlZeroMemory(VgaCrtcRegisters, sizeof(VgaCrtcRegisters));
2539 RtlZeroMemory(VgaAcRegisters , sizeof(VgaAcRegisters ));
2540
2541 /* Initialize the VGA palette and fail if it isn't successfully created */
2542 if (!VgaInitializePalette()) return FALSE;
2543 /***/ VgaResetPalette(); /***/
2544
2545 /* Switch to the text buffer, but do not enter into a text mode */
2546 VgaSetActiveScreenBuffer(TextConsoleBuffer);
2547
2548 /* Reset the sequencer */
2549 VgaResetSequencer();
2550
2551 /* Clear the VGA memory */
2552 VgaClearMemory();
2553
2554 /* Register the I/O Ports */
2555 RegisterIoPort(0x3CC, VgaReadPort, NULL); // VGA_MISC_READ
2556 RegisterIoPort(0x3C2, VgaReadPort, VgaWritePort); // VGA_MISC_WRITE, VGA_INSTAT0_READ
2557 RegisterIoPort(0x3CA, VgaReadPort, NULL); // VGA_FEATURE_READ
2558 RegisterIoPort(0x3C0, VgaReadPort, VgaWritePort); // VGA_AC_INDEX, VGA_AC_WRITE
2559 RegisterIoPort(0x3C1, VgaReadPort, NULL); // VGA_AC_READ
2560 RegisterIoPort(0x3C4, VgaReadPort, VgaWritePort); // VGA_SEQ_INDEX
2561 RegisterIoPort(0x3C5, VgaReadPort, VgaWritePort); // VGA_SEQ_DATA
2562 RegisterIoPort(0x3C6, VgaReadPort, VgaWritePort); // VGA_DAC_MASK
2563 RegisterIoPort(0x3C7, VgaReadPort, VgaWritePort); // VGA_DAC_READ_INDEX
2564 RegisterIoPort(0x3C8, VgaReadPort, VgaWritePort); // VGA_DAC_WRITE_INDEX
2565 RegisterIoPort(0x3C9, VgaReadPort, VgaWritePort); // VGA_DAC_DATA
2566 RegisterIoPort(0x3CE, VgaReadPort, VgaWritePort); // VGA_GC_INDEX
2567 RegisterIoPort(0x3CF, VgaReadPort, VgaWritePort); // VGA_GC_DATA
2568
2569 /* CGA ports for compatibility, unimplemented */
2570 RegisterIoPort(0x3D8, VgaReadPort, VgaWritePort); // CGA_MODE_CTRL_REG
2571 RegisterIoPort(0x3D9, VgaReadPort, VgaWritePort); // CGA_PAL_CTRL_REG
2572
2573 HSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(31469), VgaHorizontalRetrace);
2574 VSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(60), VgaVerticalRetrace);
2575
2576 /* Return success */
2577 return TRUE;
2578 }
2579
2580 VOID VgaCleanup(VOID)
2581 {
2582 /* Do a final display refresh */
2583 VgaRefreshDisplay();
2584
2585 DestroyHardwareTimer(VSyncTimer);
2586 DestroyHardwareTimer(HSyncTimer);
2587
2588 /* Leave the current video mode */
2589 if (ScreenMode == GRAPHICS_MODE)
2590 VgaLeaveGraphicsMode();
2591 else
2592 VgaLeaveTextMode();
2593
2594 VgaDetachFromConsole();
2595 MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
2596
2597 CloseHandle(AnotherEvent);
2598 CloseHandle(EndEvent);
2599 CloseHandle(StartEvent);
2600 }
2601
2602 /* EOF */