caa6332009c4059afd5e548e78dc12696db79f23
[reactos.git] / reactos / subsystems / ntvdm / hardware / vga.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: vga.c
5 * PURPOSE: VGA hardware emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #define NDEBUG
12
13 #include "emulator.h"
14 #include "vga.h"
15 #include "../bios/vidbios.h"
16
17 #include "io.h"
18
19 /* PRIVATE VARIABLES **********************************************************/
20
21 static CONST DWORD MemoryBase[] = { 0xA0000, 0xA0000, 0xB0000, 0xB8000 };
22 static CONST DWORD MemoryLimit[] = { 0xAFFFF, 0xAFFFF, 0xB7FFF, 0xBFFFF };
23
24 /*
25 * Activate this line if you want to use the real
26 * RegisterConsoleVDM API of ReactOS/Windows.
27 */
28 // #define USE_REAL_REGISTERCONSOLEVDM
29
30 #define USE_REACTOS_COLORS
31 // #define USE_DOSBOX_COLORS
32
33 #if defined(USE_REACTOS_COLORS)
34
35 // ReactOS colors
36 static CONST COLORREF VgaDefaultPalette[VGA_MAX_COLORS] =
37 {
38 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
39 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
40 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
41 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
42 RGB(0x00, 0x00, 0x00), RGB(0x10, 0x10, 0x10), RGB(0x20, 0x20, 0x20), RGB(0x35, 0x35, 0x35),
43 RGB(0x45, 0x45, 0x45), RGB(0x55, 0x55, 0x55), RGB(0x65, 0x65, 0x65), RGB(0x75, 0x75, 0x75),
44 RGB(0x8A, 0x8A, 0x8A), RGB(0x9A, 0x9A, 0x9A), RGB(0xAA, 0xAA, 0xAA), RGB(0xBA, 0xBA, 0xBA),
45 RGB(0xCA, 0xCA, 0xCA), RGB(0xDF, 0xDF, 0xDF), RGB(0xEF, 0xEF, 0xEF), RGB(0xFF, 0xFF, 0xFF),
46 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x82, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
47 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x82), RGB(0xFF, 0x00, 0x41),
48 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x82, 0x00), RGB(0xFF, 0xBE, 0x00),
49 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x82, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
50 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x82), RGB(0x00, 0xFF, 0xBE),
51 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x82, 0xFF), RGB(0x00, 0x41, 0xFF),
52 RGB(0x82, 0x82, 0xFF), RGB(0x9E, 0x82, 0xFF), RGB(0xBE, 0x82, 0xFF), RGB(0xDF, 0x82, 0xFF),
53 RGB(0xFF, 0x82, 0xFF), RGB(0xFF, 0x82, 0xDF), RGB(0xFF, 0x82, 0xBE), RGB(0xFF, 0x82, 0x9E),
54 RGB(0xFF, 0x82, 0x82), RGB(0xFF, 0x9E, 0x82), RGB(0xFF, 0xBE, 0x82), RGB(0xFF, 0xDF, 0x82),
55 RGB(0xFF, 0xFF, 0x82), RGB(0xDF, 0xFF, 0x82), RGB(0xBE, 0xFF, 0x82), RGB(0x9E, 0xFF, 0x82),
56 RGB(0x82, 0xFF, 0x82), RGB(0x82, 0xFF, 0x9E), RGB(0x82, 0xFF, 0xBE), RGB(0x82, 0xFF, 0xDF),
57 RGB(0x82, 0xFF, 0xFF), RGB(0x82, 0xDF, 0xFF), RGB(0x82, 0xBE, 0xFF), RGB(0x82, 0x9E, 0xFF),
58 RGB(0xBA, 0xBA, 0xFF), RGB(0xCA, 0xBA, 0xFF), RGB(0xDF, 0xBA, 0xFF), RGB(0xEF, 0xBA, 0xFF),
59 RGB(0xFF, 0xBA, 0xFF), RGB(0xFF, 0xBA, 0xEF), RGB(0xFF, 0xBA, 0xDF), RGB(0xFF, 0xBA, 0xCA),
60 RGB(0xFF, 0xBA, 0xBA), RGB(0xFF, 0xCA, 0xBA), RGB(0xFF, 0xDF, 0xBA), RGB(0xFF, 0xEF, 0xBA),
61 RGB(0xFF, 0xFF, 0xBA), RGB(0xEF, 0xFF, 0xBA), RGB(0xDF, 0xFF, 0xBA), RGB(0xCA, 0xFF, 0xBA),
62 RGB(0xBA, 0xFF, 0xBA), RGB(0xBA, 0xFF, 0xCA), RGB(0xBA, 0xFF, 0xDF), RGB(0xBA, 0xFF, 0xEF),
63 RGB(0xBA, 0xFF, 0xFF), RGB(0xBA, 0xEF, 0xFF), RGB(0xBA, 0xDF, 0xFF), RGB(0xBA, 0xCA, 0xFF),
64 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x39, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
65 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x39), RGB(0x71, 0x00, 0x1C),
66 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x39, 0x00), RGB(0x71, 0x55, 0x00),
67 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x39, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
68 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x39), RGB(0x00, 0x71, 0x55),
69 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x39, 0x71), RGB(0x00, 0x1C, 0x71),
70 RGB(0x39, 0x39, 0x71), RGB(0x45, 0x39, 0x71), RGB(0x55, 0x39, 0x71), RGB(0x61, 0x39, 0x71),
71 RGB(0x71, 0x39, 0x71), RGB(0x71, 0x39, 0x61), RGB(0x71, 0x39, 0x55), RGB(0x71, 0x39, 0x45),
72 RGB(0x71, 0x39, 0x39), RGB(0x71, 0x45, 0x39), RGB(0x71, 0x55, 0x39), RGB(0x71, 0x61, 0x39),
73 RGB(0x71, 0x71, 0x39), RGB(0x61, 0x71, 0x39), RGB(0x55, 0x71, 0x39), RGB(0x45, 0x71, 0x39),
74 RGB(0x39, 0x71, 0x39), RGB(0x39, 0x71, 0x45), RGB(0x39, 0x71, 0x55), RGB(0x39, 0x71, 0x61),
75 RGB(0x39, 0x71, 0x71), RGB(0x39, 0x61, 0x71), RGB(0x39, 0x55, 0x71), RGB(0x39, 0x45, 0x71),
76 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
77 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
78 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
79 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
80 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
81 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
82 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x31, 0x00, 0x41),
83 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x31), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
84 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x31, 0x00),
85 RGB(0x41, 0x41, 0x00), RGB(0x31, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
86 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x31),
87 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x31, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
88 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x31, 0x20, 0x41), RGB(0x39, 0x20, 0x41),
89 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x39), RGB(0x41, 0x20, 0x31), RGB(0x41, 0x20, 0x28),
90 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x31, 0x20), RGB(0x41, 0x39, 0x20),
91 RGB(0x41, 0x41, 0x20), RGB(0x39, 0x41, 0x20), RGB(0x31, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
92 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x31), RGB(0x20, 0x41, 0x39),
93 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x39, 0x41), RGB(0x20, 0x31, 0x41), RGB(0x20, 0x28, 0x41),
94 RGB(0x2D, 0x2D, 0x41), RGB(0x31, 0x2D, 0x41), RGB(0x35, 0x2D, 0x41), RGB(0x3D, 0x2D, 0x41),
95 RGB(0x41, 0x2D, 0x41), RGB(0x41, 0x2D, 0x3D), RGB(0x41, 0x2D, 0x35), RGB(0x41, 0x2D, 0x31),
96 RGB(0x41, 0x2D, 0x2D), RGB(0x41, 0x31, 0x2D), RGB(0x41, 0x35, 0x2D), RGB(0x41, 0x3D, 0x2D),
97 RGB(0x41, 0x41, 0x2D), RGB(0x3D, 0x41, 0x2D), RGB(0x35, 0x41, 0x2D), RGB(0x31, 0x41, 0x2D),
98 RGB(0x2D, 0x41, 0x2D), RGB(0x2D, 0x41, 0x31), RGB(0x2D, 0x41, 0x35), RGB(0x2D, 0x41, 0x3D),
99 RGB(0x2D, 0x41, 0x41), RGB(0x2D, 0x3D, 0x41), RGB(0x2D, 0x35, 0x41), RGB(0x2D, 0x31, 0x41),
100 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
101 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
102 };
103
104 #elif defined(USE_DOSBOX_COLORS)
105
106 // DOSBox colors
107 static CONST COLORREF VgaDefaultPalette[VGA_MAX_COLORS] =
108 {
109 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xAA), RGB(0x00, 0xAA, 0x00), RGB(0x00, 0xAA, 0xAA),
110 RGB(0xAA, 0x00, 0x00), RGB(0xAA, 0x00, 0xAA), RGB(0xAA, 0x55, 0x00), RGB(0xAA, 0xAA, 0xAA),
111 RGB(0x55, 0x55, 0x55), RGB(0x55, 0x55, 0xFF), RGB(0x55, 0xFF, 0x55), RGB(0x55, 0xFF, 0xFF),
112 RGB(0xFF, 0x55, 0x55), RGB(0xFF, 0x55, 0xFF), RGB(0xFF, 0xFF, 0x55), RGB(0xFF, 0xFF, 0xFF),
113 RGB(0x00, 0x00, 0x00), RGB(0x14, 0x14, 0x14), RGB(0x20, 0x20, 0x20), RGB(0x2C, 0x2C, 0x2C),
114 RGB(0x38, 0x38, 0x38), RGB(0x45, 0x45, 0x45), RGB(0x51, 0x51, 0x51), RGB(0x61, 0x61, 0x61),
115 RGB(0x71, 0x71, 0x71), RGB(0x82, 0x82, 0x82), RGB(0x92, 0x92, 0x92), RGB(0xA2, 0xA2, 0xA2),
116 RGB(0xB6, 0xB6, 0xB6), RGB(0xCB, 0xCB, 0xCB), RGB(0xE3, 0xE3, 0xE3), RGB(0xFF, 0xFF, 0xFF),
117 RGB(0x00, 0x00, 0xFF), RGB(0x41, 0x00, 0xFF), RGB(0x7D, 0x00, 0xFF), RGB(0xBE, 0x00, 0xFF),
118 RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0x00, 0xBE), RGB(0xFF, 0x00, 0x7D), RGB(0xFF, 0x00, 0x41),
119 RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x41, 0x00), RGB(0xFF, 0x7D, 0x00), RGB(0xFF, 0xBE, 0x00),
120 RGB(0xFF, 0xFF, 0x00), RGB(0xBE, 0xFF, 0x00), RGB(0x7D, 0xFF, 0x00), RGB(0x41, 0xFF, 0x00),
121 RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0x41), RGB(0x00, 0xFF, 0x7D), RGB(0x00, 0xFF, 0xBE),
122 RGB(0x00, 0xFF, 0xFF), RGB(0x00, 0xBE, 0xFF), RGB(0x00, 0x7D, 0xFF), RGB(0x00, 0x41, 0xFF),
123 RGB(0x7D, 0x7D, 0xFF), RGB(0x9E, 0x7D, 0xFF), RGB(0xBE, 0x7D, 0xFF), RGB(0xDF, 0x7D, 0xFF),
124 RGB(0xFF, 0x7D, 0xFF), RGB(0xFF, 0x7D, 0xDF), RGB(0xFF, 0x7D, 0xBE), RGB(0xFF, 0x7D, 0x9E),
125
126 RGB(0xFF, 0x7D, 0x7D), RGB(0xFF, 0x9E, 0x7D), RGB(0xFF, 0xBE, 0x7D), RGB(0xFF, 0xDF, 0x7D),
127 RGB(0xFF, 0xFF, 0x7D), RGB(0xDF, 0xFF, 0x7D), RGB(0xBE, 0xFF, 0x7D), RGB(0x9E, 0xFF, 0x7D),
128 RGB(0x7D, 0xFF, 0x7D), RGB(0x7D, 0xFF, 0x9E), RGB(0x7D, 0xFF, 0xBE), RGB(0x7D, 0xFF, 0xDF),
129 RGB(0x7D, 0xFF, 0xFF), RGB(0x7D, 0xDF, 0xFF), RGB(0x7D, 0xBE, 0xFF), RGB(0x7D, 0x9E, 0xFF),
130 RGB(0xB6, 0xB6, 0xFF), RGB(0xC7, 0xB6, 0xFF), RGB(0xDB, 0xB6, 0xFF), RGB(0xEB, 0xB6, 0xFF),
131 RGB(0xFF, 0xB6, 0xFF), RGB(0xFF, 0xB6, 0xEB), RGB(0xFF, 0xB6, 0xDB), RGB(0xFF, 0xB6, 0xC7),
132 RGB(0xFF, 0xB6, 0xB6), RGB(0xFF, 0xC7, 0xB6), RGB(0xFF, 0xDB, 0xB6), RGB(0xFF, 0xEB, 0xB6),
133 RGB(0xFF, 0xFF, 0xB6), RGB(0xEB, 0xFF, 0xB6), RGB(0xDB, 0xFF, 0xB6), RGB(0xC7, 0xFF, 0xB6),
134 RGB(0xB6, 0xFF, 0xB6), RGB(0xB6, 0xFF, 0xC7), RGB(0xB6, 0xFF, 0xDB), RGB(0xB6, 0xFF, 0xEB),
135 RGB(0xB6, 0xFF, 0xFF), RGB(0xB6, 0xEB, 0xFF), RGB(0xB6, 0xDB, 0xFF), RGB(0xB6, 0xC7, 0xFF),
136 RGB(0x00, 0x00, 0x71), RGB(0x1C, 0x00, 0x71), RGB(0x38, 0x00, 0x71), RGB(0x55, 0x00, 0x71),
137 RGB(0x71, 0x00, 0x71), RGB(0x71, 0x00, 0x55), RGB(0x71, 0x00, 0x38), RGB(0x71, 0x00, 0x1C),
138 RGB(0x71, 0x00, 0x00), RGB(0x71, 0x1C, 0x00), RGB(0x71, 0x38, 0x00), RGB(0x71, 0x55, 0x00),
139 RGB(0x71, 0x71, 0x00), RGB(0x55, 0x71, 0x00), RGB(0x38, 0x71, 0x00), RGB(0x1C, 0x71, 0x00),
140 RGB(0x00, 0x71, 0x00), RGB(0x00, 0x71, 0x1C), RGB(0x00, 0x71, 0x38), RGB(0x00, 0x71, 0x55),
141 RGB(0x00, 0x71, 0x71), RGB(0x00, 0x55, 0x71), RGB(0x00, 0x38, 0x71), RGB(0x00, 0x1C, 0x71),
142
143 RGB(0x38, 0x38, 0x71), RGB(0x45, 0x38, 0x71), RGB(0x55, 0x38, 0x71), RGB(0x61, 0x38, 0x71),
144 RGB(0x71, 0x38, 0x71), RGB(0x71, 0x38, 0x61), RGB(0x71, 0x38, 0x55), RGB(0x71, 0x38, 0x45),
145 RGB(0x71, 0x38, 0x38), RGB(0x71, 0x45, 0x38), RGB(0x71, 0x55, 0x38), RGB(0x71, 0x61, 0x38),
146 RGB(0x71, 0x71, 0x38), RGB(0x61, 0x71, 0x38), RGB(0x55, 0x71, 0x38), RGB(0x45, 0x71, 0x38),
147 RGB(0x38, 0x71, 0x38), RGB(0x38, 0x71, 0x45), RGB(0x38, 0x71, 0x55), RGB(0x38, 0x71, 0x61),
148 RGB(0x38, 0x71, 0x71), RGB(0x38, 0x61, 0x71), RGB(0x38, 0x55, 0x71), RGB(0x38, 0x45, 0x71),
149 RGB(0x51, 0x51, 0x71), RGB(0x59, 0x51, 0x71), RGB(0x61, 0x51, 0x71), RGB(0x69, 0x51, 0x71),
150 RGB(0x71, 0x51, 0x71), RGB(0x71, 0x51, 0x69), RGB(0x71, 0x51, 0x61), RGB(0x71, 0x51, 0x59),
151 RGB(0x71, 0x51, 0x51), RGB(0x71, 0x59, 0x51), RGB(0x71, 0x61, 0x51), RGB(0x71, 0x69, 0x51),
152 RGB(0x71, 0x71, 0x51), RGB(0x69, 0x71, 0x51), RGB(0x61, 0x71, 0x51), RGB(0x59, 0x71, 0x51),
153 RGB(0x51, 0x71, 0x51), RGB(0x51, 0x71, 0x59), RGB(0x51, 0x71, 0x61), RGB(0x51, 0x71, 0x69),
154 RGB(0x51, 0x71, 0x71), RGB(0x51, 0x69, 0x71), RGB(0x51, 0x61, 0x71), RGB(0x51, 0x59, 0x71),
155 RGB(0x00, 0x00, 0x41), RGB(0x10, 0x00, 0x41), RGB(0x20, 0x00, 0x41), RGB(0x30, 0x00, 0x41),
156 RGB(0x41, 0x00, 0x41), RGB(0x41, 0x00, 0x30), RGB(0x41, 0x00, 0x20), RGB(0x41, 0x00, 0x10),
157 RGB(0x41, 0x00, 0x00), RGB(0x41, 0x10, 0x00), RGB(0x41, 0x20, 0x00), RGB(0x41, 0x30, 0x00),
158 RGB(0x41, 0x41, 0x00), RGB(0x30, 0x41, 0x00), RGB(0x20, 0x41, 0x00), RGB(0x10, 0x41, 0x00),
159
160 RGB(0x00, 0x41, 0x00), RGB(0x00, 0x41, 0x10), RGB(0x00, 0x41, 0x20), RGB(0x00, 0x41, 0x30),
161 RGB(0x00, 0x41, 0x41), RGB(0x00, 0x30, 0x41), RGB(0x00, 0x20, 0x41), RGB(0x00, 0x10, 0x41),
162 RGB(0x20, 0x20, 0x41), RGB(0x28, 0x20, 0x41), RGB(0x30, 0x20, 0x41), RGB(0x38, 0x20, 0x41),
163 RGB(0x41, 0x20, 0x41), RGB(0x41, 0x20, 0x38), RGB(0x41, 0x20, 0x30), RGB(0x41, 0x20, 0x28),
164 RGB(0x41, 0x20, 0x20), RGB(0x41, 0x28, 0x20), RGB(0x41, 0x30, 0x20), RGB(0x41, 0x38, 0x20),
165 RGB(0x41, 0x41, 0x20), RGB(0x38, 0x41, 0x20), RGB(0x30, 0x41, 0x20), RGB(0x28, 0x41, 0x20),
166 RGB(0x20, 0x41, 0x20), RGB(0x20, 0x41, 0x28), RGB(0x20, 0x41, 0x30), RGB(0x20, 0x41, 0x38),
167 RGB(0x20, 0x41, 0x41), RGB(0x20, 0x38, 0x41), RGB(0x20, 0x30, 0x41), RGB(0x20, 0x28, 0x41),
168 RGB(0x2C, 0x2C, 0x41), RGB(0x30, 0x2C, 0x41), RGB(0x34, 0x2C, 0x41), RGB(0x3C, 0x2C, 0x41),
169 RGB(0x41, 0x2C, 0x41), RGB(0x41, 0x2C, 0x3C), RGB(0x41, 0x2C, 0x34), RGB(0x41, 0x2C, 0x30),
170 RGB(0x41, 0x2C, 0x2C), RGB(0x41, 0x30, 0x2C), RGB(0x41, 0x34, 0x2C), RGB(0x41, 0x3C, 0x2C),
171 RGB(0x41, 0x41, 0x2C), RGB(0x3C, 0x41, 0x2C), RGB(0x34, 0x41, 0x2C), RGB(0x30, 0x41, 0x2C),
172 RGB(0x2C, 0x41, 0x2C), RGB(0x2C, 0x41, 0x30), RGB(0x2C, 0x41, 0x34), RGB(0x2C, 0x41, 0x3C),
173 RGB(0x2C, 0x41, 0x41), RGB(0x2C, 0x3C, 0x41), RGB(0x2C, 0x34, 0x41), RGB(0x2C, 0x30, 0x41),
174 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00),
175 RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x00)
176 };
177
178 #endif
179
180 /*
181 * Default 16-color palette for foreground and background
182 * (corresponding flags in comments).
183 * Taken from subsystems/win32/winsrv/consrv/frontends/gui/conwnd.c
184 */
185 static const COLORREF ConsoleColors[16] =
186 {
187 RGB(0, 0, 0), // (Black)
188 RGB(0, 0, 128), // BLUE
189 RGB(0, 128, 0), // GREEN
190 RGB(0, 128, 128), // BLUE | GREEN
191 RGB(128, 0, 0), // RED
192 RGB(128, 0, 128), // BLUE | RED
193 RGB(128, 128, 0), // GREEN | RED
194 RGB(192, 192, 192), // BLUE | GREEN | RED
195
196 RGB(128, 128, 128), // (Grey) INTENSITY
197 RGB(0, 0, 255), // BLUE | INTENSITY
198 RGB(0, 255, 0), // GREEN | INTENSITY
199 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
200 RGB(255, 0, 0), // RED | INTENSITY
201 RGB(255, 0, 255), // BLUE | RED | INTENSITY
202 RGB(255, 255, 0), // GREEN | RED | INTENSITY
203 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
204 };
205
206 /*
207 * Console interface -- VGA-mode-agnostic
208 */
209 typedef struct _CHAR_CELL
210 {
211 CHAR Char;
212 BYTE Attributes;
213 } CHAR_CELL, *PCHAR_CELL;
214 C_ASSERT(sizeof(CHAR_CELL) == 2);
215
216 static LPVOID ConsoleFramebuffer = NULL; // Active framebuffer, points to
217 // either TextFramebuffer or a valid
218 // graphics framebuffer.
219 static HPALETTE TextPaletteHandle = NULL;
220 static HPALETTE PaletteHandle = NULL;
221
222 static HANDLE StartEvent = NULL;
223 static HANDLE EndEvent = NULL;
224 static HANDLE AnotherEvent = NULL;
225
226 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo;
227 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo;
228
229
230 /*
231 * Text mode -- we always keep a valid text mode framebuffer
232 * even if we are in graphics mode. This is needed in order to
233 * keep a consistent VGA state.
234 */
235 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
236 static COORD TextResolution = {0};
237 static PCHAR_CELL TextFramebuffer = NULL;
238 static HANDLE TextConsoleBuffer = NULL;
239
240 /* Graphics mode */
241 static HANDLE GraphicsConsoleBuffer = NULL;
242 static HANDLE ConsoleMutex = NULL;
243 static BOOLEAN DoubleVision = FALSE;
244
245 /*
246 * VGA Hardware
247 */
248 static BYTE VgaMemory[VGA_NUM_BANKS * VGA_BANK_SIZE];
249
250 static BYTE VgaLatchRegisters[VGA_NUM_BANKS] = {0, 0, 0, 0};
251
252 static BYTE VgaMiscRegister;
253 static BYTE VgaFeatureRegister;
254
255 static BYTE VgaSeqIndex = VGA_SEQ_RESET_REG;
256 static BYTE VgaSeqRegisters[VGA_SEQ_MAX_REG];
257
258 static BYTE VgaCrtcIndex = VGA_CRTC_HORZ_TOTAL_REG;
259 static BYTE VgaCrtcRegisters[VGA_CRTC_MAX_REG];
260
261 static BYTE VgaGcIndex = VGA_GC_RESET_REG;
262 static BYTE VgaGcRegisters[VGA_GC_MAX_REG];
263
264 static BOOLEAN VgaAcLatch = FALSE;
265 static BOOLEAN VgaAcPalDisable = TRUE;
266 static BYTE VgaAcIndex = VGA_AC_PAL_0_REG;
267 static BYTE VgaAcRegisters[VGA_AC_MAX_REG];
268
269 // static VGA_REGISTERS VgaRegisters;
270
271 static BYTE VgaDacMask = 0xFF;
272 static WORD VgaDacIndex = 0;
273 static BOOLEAN VgaDacReadWrite = FALSE;
274 static BYTE VgaDacRegisters[VGA_PALETTE_SIZE];
275
276 static BOOLEAN InVerticalRetrace = FALSE;
277 static BOOLEAN InHorizontalRetrace = FALSE;
278
279 static BOOLEAN NeedsUpdate = FALSE;
280 static BOOLEAN ModeChanged = FALSE;
281 static BOOLEAN CursorMoved = FALSE;
282 static BOOLEAN PaletteChanged = FALSE;
283
284 static
285 enum SCREEN_MODE
286 {
287 TEXT_MODE,
288 GRAPHICS_MODE
289 } ScreenMode = TEXT_MODE;
290
291 static SMALL_RECT UpdateRectangle = { 0, 0, 0, 0 };
292
293 /* RegisterConsoleVDM EMULATION ***********************************************/
294
295 #include <ntddvdeo.h>
296
297 #ifdef USE_REAL_REGISTERCONSOLEVDM
298
299 #define __RegisterConsoleVDM RegisterConsoleVDM
300 #define __InvalidateConsoleDIBits InvalidateConsoleDIBits
301
302 #else
303
304 /*
305 * This private buffer, per-console, is used by
306 * RegisterConsoleVDM and InvalidateConsoleDIBits.
307 */
308 static COORD VDMBufferSize = {0};
309 static PCHAR_CELL VDMBuffer = NULL;
310
311 static PCHAR_INFO CharBuff = NULL; // This is a hack, which is unneeded
312 // for the real RegisterConsoleVDM and
313 // InvalidateConsoleDIBits
314
315 BOOL
316 WINAPI
317 __RegisterConsoleVDM(IN DWORD dwRegisterFlags,
318 IN HANDLE hStartHardwareEvent,
319 IN HANDLE hEndHardwareEvent,
320 IN HANDLE hErrorHardwareEvent,
321 IN DWORD dwUnusedVar,
322 OUT LPDWORD lpVideoStateLength,
323 OUT PVOID* lpVideoState, // PVIDEO_HARDWARE_STATE_HEADER*
324 IN PVOID lpUnusedBuffer,
325 IN DWORD dwUnusedBufferLength,
326 IN COORD dwVDMBufferSize,
327 OUT PVOID* lpVDMBuffer)
328 {
329 UNREFERENCED_PARAMETER(hErrorHardwareEvent);
330 UNREFERENCED_PARAMETER(dwUnusedVar);
331 UNREFERENCED_PARAMETER(lpVideoStateLength);
332 UNREFERENCED_PARAMETER(lpVideoState);
333 UNREFERENCED_PARAMETER(lpUnusedBuffer);
334 UNREFERENCED_PARAMETER(dwUnusedBufferLength);
335
336 SetLastError(0);
337 DPRINT1("__RegisterConsoleVDM(%d)\n", dwRegisterFlags);
338
339 if (lpVDMBuffer == NULL) return FALSE;
340
341 if (dwRegisterFlags != 0)
342 {
343 // if (hStartHardwareEvent == NULL || hEndHardwareEvent == NULL) return FALSE;
344 if (VDMBuffer != NULL) return FALSE;
345
346 VDMBufferSize = dwVDMBufferSize;
347
348 /* HACK: Cache -- to be removed in the real implementation */
349 CharBuff = HeapAlloc(GetProcessHeap(),
350 HEAP_ZERO_MEMORY,
351 VDMBufferSize.X * VDMBufferSize.Y
352 * sizeof(CHAR_INFO));
353 ASSERT(CharBuff);
354
355 VDMBuffer = HeapAlloc(GetProcessHeap(),
356 HEAP_ZERO_MEMORY,
357 VDMBufferSize.X * VDMBufferSize.Y
358 * sizeof(CHAR_CELL));
359 *lpVDMBuffer = VDMBuffer;
360 return (VDMBuffer != NULL);
361 }
362 else
363 {
364 /* HACK: Cache -- to be removed in the real implementation */
365 if (CharBuff) HeapFree(GetProcessHeap(), 0, CharBuff);
366 CharBuff = NULL;
367
368 if (VDMBuffer) HeapFree(GetProcessHeap(), 0, VDMBuffer);
369 VDMBuffer = NULL;
370
371 VDMBufferSize.X = VDMBufferSize.Y = 0;
372
373 return TRUE;
374 }
375 }
376
377 BOOL
378 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput,
379 IN PSMALL_RECT lpRect)
380 {
381 if ((hConsoleOutput == TextConsoleBuffer) && (VDMBuffer != NULL))
382 {
383 /* HACK: Write the cached data to the console */
384
385 COORD Origin = { lpRect->Left, lpRect->Top };
386 SHORT i, j;
387
388 ASSERT(CharBuff);
389
390 for (i = 0; i < VDMBufferSize.Y; i++)
391 {
392 for (j = 0; j < VDMBufferSize.X; j++)
393 {
394 CharBuff[i * VDMBufferSize.X + j].Char.AsciiChar = VDMBuffer[i * VDMBufferSize.X + j].Char;
395 CharBuff[i * VDMBufferSize.X + j].Attributes = VDMBuffer[i * VDMBufferSize.X + j].Attributes;
396 }
397 }
398
399 WriteConsoleOutputA(hConsoleOutput,
400 CharBuff,
401 VDMBufferSize,
402 Origin,
403 lpRect);
404 }
405
406 return InvalidateConsoleDIBits(hConsoleOutput, lpRect);
407 }
408
409 #endif
410
411 /* PRIVATE FUNCTIONS **********************************************************/
412
413 static inline DWORD VgaGetAddressSize(VOID);
414 static VOID VgaUpdateTextCursor(VOID);
415
416 static VOID VgaUpdateCursorPosition(VOID)
417 {
418 /*
419 * Update the cursor position in the VGA registers.
420 */
421 WORD Offset = ConsoleInfo.dwCursorPosition.Y * TextResolution.X +
422 ConsoleInfo.dwCursorPosition.X;
423
424 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG] = LOBYTE(Offset);
425 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG] = HIBYTE(Offset);
426
427 // VidBiosSyncCursorPosition();
428 VgaUpdateTextCursor();
429 }
430
431 static BOOL VgaAttachToConsoleInternal(PCOORD Resolution)
432 {
433 BOOL Success;
434 ULONG Length = 0;
435 PVIDEO_HARDWARE_STATE_HEADER State;
436
437 #ifdef USE_REAL_REGISTERCONSOLEVDM
438 PCHAR_INFO CharBuff = NULL;
439 #endif
440 SHORT i, j;
441 DWORD AddressSize, ScanlineSize;
442 DWORD Address = 0;
443 DWORD CurrentAddr;
444 SMALL_RECT ConRect;
445 COORD Origin = { 0, 0 };
446
447 ASSERT(TextFramebuffer == NULL);
448
449 TextResolution = *Resolution;
450
451 /*
452 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
453 * in the two following APIs:
454 * SrvRegisterConsoleVDM (corresponding Win32 API: RegisterConsoleVDM)
455 * SrvVDMConsoleOperation (corresponding Win32 API: )
456 * to check whether the current process is a VDM process, and fails otherwise with the
457 * error 0xC0000022 ().
458 *
459 * It is worth it to notice that also basesrv.dll does the same only for the
460 * BaseSrvIsFirstVDM API...
461 */
462
463 Success =
464 __RegisterConsoleVDM(1,
465 StartEvent,
466 EndEvent,
467 AnotherEvent, // NULL,
468 0,
469 &Length, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
470 (PVOID*)&State, // NULL,
471 NULL,
472 0,
473 TextResolution,
474 (PVOID*)&TextFramebuffer);
475 if (!Success)
476 {
477 DisplayMessage(L"RegisterConsoleVDM failed with error %d\n", GetLastError());
478 EmulatorTerminate();
479 return FALSE;
480 }
481
482 #ifdef USE_REAL_REGISTERCONSOLEVDM
483 CharBuff = HeapAlloc(GetProcessHeap(),
484 HEAP_ZERO_MEMORY,
485 TextResolution.X * TextResolution.Y
486 * sizeof(CHAR_INFO));
487 ASSERT(CharBuff);
488 #endif
489
490 /*
491 * Resize the console
492 */
493 ConRect.Left = 0;
494 ConRect.Top = ConsoleInfo.srWindow.Top;
495 ConRect.Right = ConRect.Left + Resolution->X - 1;
496 ConRect.Bottom = ConRect.Top + Resolution->Y - 1;
497 /*
498 * Use this trick to effectively resize the console buffer and window,
499 * because:
500 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
501 * is smaller than the current console window size, and:
502 * - SetConsoleWindowInfo fails if the new console window size is larger
503 * than the current console screen buffer size.
504 */
505 SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
506 SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
507 SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
508 /* Update the saved console information */
509 GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
510
511 /*
512 * Copy console data into VGA memory
513 */
514
515 /* Get the data */
516 AddressSize = VgaGetAddressSize();
517 ConRect.Left = ConRect.Top = 0;
518 ConRect.Right = TextResolution.X;
519 ConRect.Bottom = TextResolution.Y;
520 ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
521
522 /* Read the data from the console into the framebuffer... */
523 ReadConsoleOutputA(TextConsoleBuffer,
524 CharBuff,
525 TextResolution,
526 Origin,
527 &ConRect);
528
529 /* ... and copy the framebuffer into the VGA memory */
530
531 /* Loop through the scanlines */
532 for (i = 0; i < TextResolution.Y; i++)
533 {
534 /* Loop through the characters */
535 for (j = 0; j < TextResolution.X; j++)
536 {
537 CurrentAddr = LOWORD((Address + j) * AddressSize);
538
539 /* Store the character in plane 0 */
540 VgaMemory[CurrentAddr] = CharBuff[i * TextResolution.X + j].Char.AsciiChar;
541
542 /* Store the attribute in plane 1 */
543 VgaMemory[CurrentAddr + VGA_BANK_SIZE] = (BYTE)CharBuff[i * TextResolution.X + j].Attributes;
544 }
545
546 /* Move to the next scanline */
547 Address += ScanlineSize;
548 }
549
550 #ifdef USE_REAL_REGISTERCONSOLEVDM
551 if (CharBuff) HeapFree(GetProcessHeap(), 0, CharBuff);
552 #endif
553
554 VgaUpdateCursorPosition();
555
556 return TRUE;
557 }
558
559 static BOOL IsConsoleHandle(HANDLE hHandle)
560 {
561 DWORD dwMode;
562
563 /* Check whether the handle may be that of a console... */
564 if ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR)
565 return FALSE;
566
567 /*
568 * It may be. Perform another test... The idea comes from the
569 * MSDN description of the WriteConsole API:
570 *
571 * "WriteConsole fails if it is used with a standard handle
572 * that is redirected to a file. If an application processes
573 * multilingual output that can be redirected, determine whether
574 * the output handle is a console handle (one method is to call
575 * the GetConsoleMode function and check whether it succeeds).
576 * If the handle is a console handle, call WriteConsole. If the
577 * handle is not a console handle, the output is redirected and
578 * you should call WriteFile to perform the I/O."
579 */
580 return GetConsoleMode(hHandle, &dwMode);
581 }
582
583 static inline DWORD VgaGetAddressSize(VOID)
584 {
585 if (VgaCrtcRegisters[VGA_CRTC_UNDERLINE_REG] & VGA_CRTC_UNDERLINE_DWORD)
586 {
587 /* Double-word addressing */
588 return 4; // sizeof(DWORD)
589 }
590 else if (VgaCrtcRegisters[VGA_CRTC_MODE_CONTROL_REG] & VGA_CRTC_MODE_CONTROL_BYTE)
591 {
592 /* Byte addressing */
593 return 1; // sizeof(BYTE)
594 }
595 else
596 {
597 /* Word addressing */
598 return 2; // sizeof(WORD)
599 }
600 }
601
602 static inline DWORD VgaTranslateReadAddress(DWORD Address)
603 {
604 DWORD Offset = Address - VgaGetVideoBaseAddress();
605 BYTE Plane;
606
607 /* Check for chain-4 and odd-even mode */
608 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
609 {
610 /* The lowest two bits are the plane number */
611 Plane = Offset & 3;
612 Offset >>= 2;
613 }
614 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
615 {
616 /* The LSB is the plane number */
617 Plane = Offset & 1;
618 Offset >>= 1;
619 }
620 else
621 {
622 /* Use the read mode */
623 Plane = VgaGcRegisters[VGA_GC_READ_MAP_SEL_REG] & 0x03;
624 }
625
626 /* Multiply the offset by the address size */
627 Offset *= VgaGetAddressSize();
628
629 return Offset + Plane * VGA_BANK_SIZE;
630 }
631
632 static inline DWORD VgaTranslateWriteAddress(DWORD Address)
633 {
634 DWORD Offset = Address - VgaGetVideoBaseAddress();
635
636 /* Check for chain-4 and odd-even mode */
637 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
638 {
639 /* Shift the offset to the right by 2 */
640 Offset >>= 2;
641 }
642 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
643 {
644 /* Shift the offset to the right by 1 */
645 Offset >>= 1;
646 }
647
648 /* Multiply the offset by the address size */
649 Offset *= VgaGetAddressSize();
650
651 /* Return the offset on plane 0 */
652 return Offset;
653 }
654
655 static inline BYTE VgaTranslateByteForWriting(BYTE Data, BYTE Plane)
656 {
657 BYTE WriteMode = VgaGcRegisters[VGA_GC_MODE_REG] & 3;
658 BYTE BitMask = VgaGcRegisters[VGA_GC_BITMASK_REG];
659
660 if (WriteMode == 1)
661 {
662 /* In write mode 1 just return the latch register */
663 return VgaLatchRegisters[Plane];
664 }
665
666 if (WriteMode != 2)
667 {
668 /* Write modes 0 and 3 rotate the data to the right first */
669 BYTE RotateCount = VgaGcRegisters[VGA_GC_ROTATE_REG] & 7;
670 Data = LOBYTE(((DWORD)Data >> RotateCount) | ((DWORD)Data << (8 - RotateCount)));
671 }
672 else
673 {
674 /* Write mode 2 expands the appropriate bit to all 8 bits */
675 Data = (Data & (1 << Plane)) ? 0xFF : 0x00;
676 }
677
678 if (WriteMode == 0)
679 {
680 /*
681 * In write mode 0, the enable set/reset register decides if the
682 * set/reset bit should be expanded to all 8 bits.
683 */
684 if (VgaGcRegisters[VGA_GC_ENABLE_RESET_REG] & (1 << Plane))
685 {
686 /* Copy the bit from the set/reset register to all 8 bits */
687 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
688 }
689 }
690
691 if (WriteMode != 3)
692 {
693 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
694 BYTE LogicalOperation = (VgaGcRegisters[VGA_GC_ROTATE_REG] >> 3) & 3;
695
696 if (LogicalOperation == 1) Data &= VgaLatchRegisters[Plane];
697 else if (LogicalOperation == 2) Data |= VgaLatchRegisters[Plane];
698 else if (LogicalOperation == 3) Data ^= VgaLatchRegisters[Plane];
699 }
700 else
701 {
702 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
703 BitMask &= Data;
704
705 /* Then we expand the bit in the set/reset field */
706 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
707 }
708
709 /* Bits cleared in the bitmask are replaced with latch register bits */
710 Data = (Data & BitMask) | (VgaLatchRegisters[Plane] & (~BitMask));
711
712 /* Return the byte */
713 return Data;
714 }
715
716 static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column)
717 {
718 /* Check if this is the first time the rectangle is updated */
719 if (!NeedsUpdate)
720 {
721 UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT;
722 UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT;
723 }
724
725 /* Expand the rectangle to include the point */
726 UpdateRectangle.Left = min(UpdateRectangle.Left, Column);
727 UpdateRectangle.Right = max(UpdateRectangle.Right, Column);
728 UpdateRectangle.Top = min(UpdateRectangle.Top, Row);
729 UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Row);
730
731 /* Set the update request flag */
732 NeedsUpdate = TRUE;
733 }
734
735 static VOID VgaWriteSequencer(BYTE Data)
736 {
737 ASSERT(VgaSeqIndex < VGA_SEQ_MAX_REG);
738
739 /* Save the value */
740 VgaSeqRegisters[VgaSeqIndex] = Data;
741 }
742
743 static VOID VgaWriteGc(BYTE Data)
744 {
745 ASSERT(VgaGcIndex < VGA_GC_MAX_REG);
746
747 /* Save the value */
748 VgaGcRegisters[VgaGcIndex] = Data;
749
750 /* Check the index */
751 switch (VgaGcIndex)
752 {
753 case VGA_GC_MISC_REG:
754 {
755 /* The GC misc register decides if it's text or graphics mode */
756 ModeChanged = TRUE;
757 break;
758 }
759 }
760 }
761
762 static VOID VgaWriteCrtc(BYTE Data)
763 {
764 ASSERT(VgaGcIndex < VGA_CRTC_MAX_REG);
765
766 /* Save the value */
767 VgaCrtcRegisters[VgaCrtcIndex] = Data;
768
769 /* Check the index */
770 switch (VgaCrtcIndex)
771 {
772 case VGA_CRTC_END_HORZ_DISP_REG:
773 case VGA_CRTC_VERT_DISP_END_REG:
774 case VGA_CRTC_OVERFLOW_REG:
775 {
776 /* The video mode has changed */
777 ModeChanged = TRUE;
778 break;
779 }
780
781 case VGA_CRTC_CURSOR_LOC_LOW_REG:
782 case VGA_CRTC_CURSOR_LOC_HIGH_REG:
783 case VGA_CRTC_CURSOR_START_REG:
784 case VGA_CRTC_CURSOR_END_REG:
785 {
786 /* Set the cursor moved flag */
787 CursorMoved = TRUE;
788 break;
789 }
790 }
791 }
792
793 static VOID VgaWriteDac(BYTE Data)
794 {
795 INT i, PaletteIndex;
796 PALETTEENTRY Entry;
797
798 /* Set the value */
799 VgaDacRegisters[VgaDacIndex] = Data;
800
801 /* Find the palette index */
802 PaletteIndex = VgaDacIndex / 3;
803
804 /* Fill the entry structure */
805 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3]);
806 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 1]);
807 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 2]);
808 Entry.peFlags = 0;
809
810 /* Update the palette entry */
811 SetPaletteEntries(PaletteHandle, PaletteIndex, 1, &Entry);
812
813 /* Check which text palette entries are affected */
814 for (i = 0; i <= VGA_AC_PAL_F_REG; i++)
815 {
816 if (VgaAcRegisters[i] == PaletteIndex)
817 {
818 /* Update the text palette entry */
819 SetPaletteEntries(TextPaletteHandle, i, 1, &Entry);
820 }
821 }
822
823 /* Set the palette changed flag */
824 PaletteChanged = TRUE;
825
826 /* Update the index */
827 VgaDacIndex++;
828 VgaDacIndex %= VGA_PALETTE_SIZE;
829 }
830
831 static VOID VgaWriteAc(BYTE Data)
832 {
833 PALETTEENTRY Entry;
834
835 ASSERT(VgaAcIndex < VGA_AC_MAX_REG);
836
837 /* Save the value */
838 if (VgaAcIndex <= VGA_AC_PAL_F_REG)
839 {
840 if (VgaAcPalDisable) return;
841
842 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
843 if (VgaAcRegisters[VgaAcIndex] != Data)
844 {
845 /* Update the AC register */
846 VgaAcRegisters[VgaAcIndex] = Data;
847
848 /* Fill the entry structure */
849 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3]);
850 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3 + 1]);
851 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3 + 2]);
852 Entry.peFlags = 0;
853
854 /* Update the palette entry and set the palette change flag */
855 SetPaletteEntries(TextPaletteHandle, VgaAcIndex, 1, &Entry);
856 PaletteChanged = TRUE;
857 }
858 }
859 else
860 {
861 VgaAcRegisters[VgaAcIndex] = Data;
862 }
863 }
864
865 static VOID VgaRestoreDefaultPalette(PPALETTEENTRY Entries, USHORT NumOfEntries)
866 {
867 USHORT i;
868
869 /* Copy the colors of the default palette to the DAC and console palette */
870 for (i = 0; i < NumOfEntries; i++)
871 {
872 /* Set the palette entries */
873 Entries[i].peRed = GetRValue(VgaDefaultPalette[i]);
874 Entries[i].peGreen = GetGValue(VgaDefaultPalette[i]);
875 Entries[i].peBlue = GetBValue(VgaDefaultPalette[i]);
876 Entries[i].peFlags = 0;
877
878 /* Set the DAC registers */
879 VgaDacRegisters[i * 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette[i]));
880 VgaDacRegisters[i * 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette[i]));
881 VgaDacRegisters[i * 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette[i]));
882 }
883 }
884
885 static BOOLEAN VgaInitializePalette(VOID)
886 {
887 INT i;
888 BOOLEAN Result = FALSE;
889 LPLOGPALETTE Palette, TextPalette;
890
891 /* Allocate storage space for the palettes */
892 Palette = (LPLOGPALETTE)HeapAlloc(GetProcessHeap(),
893 HEAP_ZERO_MEMORY,
894 sizeof(LOGPALETTE) +
895 VGA_MAX_COLORS * sizeof(PALETTEENTRY));
896 TextPalette = (LPLOGPALETTE)HeapAlloc(GetProcessHeap(),
897 HEAP_ZERO_MEMORY,
898 sizeof(LOGPALETTE) +
899 (VGA_AC_PAL_F_REG + 1) * sizeof(PALETTEENTRY));
900 if ((Palette == NULL) || (TextPalette == NULL)) goto Cleanup;
901
902 /* Initialize the palettes */
903 Palette->palVersion = TextPalette->palVersion = 0x0300;
904 Palette->palNumEntries = VGA_MAX_COLORS;
905 TextPalette->palNumEntries = VGA_AC_PAL_F_REG + 1;
906
907 /* Restore the default graphics palette */
908 VgaRestoreDefaultPalette(Palette->palPalEntry, Palette->palNumEntries);
909
910 /* Set the default text palette */
911 for (i = 0; i < TextPalette->palNumEntries; i++)
912 {
913 /* Set the palette entries */
914 TextPalette->palPalEntry[i].peRed = GetRValue(ConsoleColors[i]);
915 TextPalette->palPalEntry[i].peGreen = GetGValue(ConsoleColors[i]);
916 TextPalette->palPalEntry[i].peBlue = GetBValue(ConsoleColors[i]);
917 TextPalette->palPalEntry[i].peFlags = 0;
918 }
919
920 /* Create the palettes */
921 PaletteHandle = CreatePalette(Palette);
922 TextPaletteHandle = CreatePalette(TextPalette);
923
924 if (PaletteHandle != NULL && TextPaletteHandle != NULL)
925 {
926 /* The palettes have been created successfully */
927 Result = TRUE;
928 }
929
930 Cleanup:
931 /* Free the palettes */
932 if (Palette) HeapFree(GetProcessHeap(), 0, Palette);
933 if (TextPalette) HeapFree(GetProcessHeap(), 0, TextPalette);
934
935 if (!Result)
936 {
937 /* Something failed, delete the palettes */
938 if (PaletteHandle) DeleteObject(PaletteHandle);
939 if (TextPaletteHandle) DeleteObject(TextPaletteHandle);
940 }
941
942 return Result;
943 }
944
945 static BOOL VgaEnterGraphicsMode(PCOORD Resolution)
946 {
947 DWORD i;
948 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo;
949 BYTE BitmapInfoBuffer[VGA_BITMAP_INFO_SIZE];
950 LPBITMAPINFO BitmapInfo = (LPBITMAPINFO)BitmapInfoBuffer;
951 LPWORD PaletteIndex = (LPWORD)(BitmapInfo->bmiColors);
952
953 LONG Width = Resolution->X;
954 LONG Height = Resolution->Y;
955
956 /* Use DoubleVision mode if the resolution is too small */
957 if (Width < VGA_MINIMUM_WIDTH && Height < VGA_MINIMUM_HEIGHT)
958 {
959 DoubleVision = TRUE;
960 Width *= 2;
961 Height *= 2;
962 }
963 else
964 {
965 DoubleVision = FALSE;
966 }
967
968 /* Fill the bitmap info header */
969 ZeroMemory(&BitmapInfo->bmiHeader, sizeof(BITMAPINFOHEADER));
970 BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
971 BitmapInfo->bmiHeader.biWidth = Width;
972 BitmapInfo->bmiHeader.biHeight = Height;
973 BitmapInfo->bmiHeader.biBitCount = 8;
974 BitmapInfo->bmiHeader.biPlanes = 1;
975 BitmapInfo->bmiHeader.biCompression = BI_RGB;
976 BitmapInfo->bmiHeader.biSizeImage = Width * Height /* * 1 == biBitCount / 8 */;
977
978 /* Fill the palette data */
979 for (i = 0; i < (VGA_PALETTE_SIZE / 3); i++) PaletteIndex[i] = (WORD)i;
980
981 /* Fill the console graphics buffer info */
982 GraphicsBufferInfo.dwBitMapInfoLength = VGA_BITMAP_INFO_SIZE;
983 GraphicsBufferInfo.lpBitMapInfo = BitmapInfo;
984 GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS;
985
986 /* Create the buffer */
987 GraphicsConsoleBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
988 FILE_SHARE_READ | FILE_SHARE_WRITE,
989 NULL,
990 CONSOLE_GRAPHICS_BUFFER,
991 &GraphicsBufferInfo);
992 if (GraphicsConsoleBuffer == INVALID_HANDLE_VALUE) return FALSE;
993
994 /* Save the framebuffer address and mutex */
995 ConsoleFramebuffer = GraphicsBufferInfo.lpBitMap;
996 ConsoleMutex = GraphicsBufferInfo.hMutex;
997
998 /* Clear the framebuffer */
999 ZeroMemory(ConsoleFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
1000
1001 /* Set the active buffer */
1002 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer);
1003
1004 /* Set the graphics mode palette */
1005 SetConsolePalette(GraphicsConsoleBuffer,
1006 PaletteHandle,
1007 SYSPAL_NOSTATIC256);
1008
1009 /* Set the screen mode flag */
1010 ScreenMode = GRAPHICS_MODE;
1011
1012 return TRUE;
1013 }
1014
1015 static VOID VgaLeaveGraphicsMode(VOID)
1016 {
1017 /* Release the console framebuffer mutex */
1018 ReleaseMutex(ConsoleMutex);
1019
1020 /* Switch back to the default console text buffer */
1021 // SetConsoleActiveScreenBuffer(TextConsoleBuffer);
1022
1023 /* Cleanup the video data */
1024 CloseHandle(ConsoleMutex);
1025 ConsoleMutex = NULL;
1026 ConsoleFramebuffer = NULL;
1027 CloseHandle(GraphicsConsoleBuffer);
1028 GraphicsConsoleBuffer = NULL;
1029 DoubleVision = FALSE;
1030 }
1031
1032 static BOOL VgaEnterTextMode(PCOORD Resolution)
1033 {
1034 DPRINT1("VgaEnterTextMode\n");
1035
1036 /* Switch to the text buffer */
1037 SetConsoleActiveScreenBuffer(TextConsoleBuffer);
1038
1039 /* Adjust the text framebuffer if we changed the resolution */
1040 if (TextResolution.X != Resolution->X ||
1041 TextResolution.Y != Resolution->Y)
1042 {
1043 VgaDetachFromConsole(TRUE);
1044
1045 /*
1046 * VgaAttachToConsoleInternal sets TextResolution to the
1047 * new resolution and updates ConsoleInfo.
1048 */
1049 if (!VgaAttachToConsoleInternal(Resolution))
1050 {
1051 DisplayMessage(L"An unexpected error occurred!\n");
1052 EmulatorTerminate();
1053 return FALSE;
1054 }
1055 }
1056 else
1057 {
1058 VgaUpdateCursorPosition();
1059 }
1060
1061 /* The active framebuffer is now the text framebuffer */
1062 ConsoleFramebuffer = TextFramebuffer;
1063
1064 /*
1065 * Set the text mode palette.
1066 *
1067 * WARNING: This call should fail on Windows (and therefore
1068 * we get the default palette and our external behaviour is
1069 * just like Windows' one), but it should success on ReactOS
1070 * (so that we get console palette changes even for text-mode
1071 * screen-buffers, which is a new feature on ReactOS).
1072 */
1073 SetConsolePalette(TextConsoleBuffer,
1074 TextPaletteHandle,
1075 SYSPAL_NOSTATIC256);
1076
1077 /* Set the screen mode flag */
1078 ScreenMode = TEXT_MODE;
1079
1080 return TRUE;
1081 }
1082
1083 static VOID VgaLeaveTextMode(VOID)
1084 {
1085 /* Reset the active framebuffer */
1086 ConsoleFramebuffer = NULL;
1087 }
1088
1089 static VOID VgaChangeMode(VOID)
1090 {
1091 COORD Resolution = VgaGetDisplayResolution();
1092
1093 if (ScreenMode == GRAPHICS_MODE)
1094 {
1095 /* Leave the current graphics mode */
1096 VgaLeaveGraphicsMode();
1097 }
1098 else
1099 {
1100 /* Leave the current text mode */
1101 VgaLeaveTextMode();
1102 }
1103
1104 /* Check if the new mode is alphanumeric */
1105 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA))
1106 {
1107 /* Enter new text mode */
1108 if (!VgaEnterTextMode(&Resolution))
1109 {
1110 DisplayMessage(L"An unexpected VGA error occurred while switching into text mode.");
1111 EmulatorTerminate();
1112 return;
1113 }
1114 }
1115 else
1116 {
1117 /* Enter graphics mode */
1118 if (!VgaEnterGraphicsMode(&Resolution))
1119 {
1120 DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode.");
1121 EmulatorTerminate();
1122 return;
1123 }
1124 }
1125
1126 /* Trigger a full update of the screen */
1127 NeedsUpdate = TRUE;
1128 UpdateRectangle.Left = 0;
1129 UpdateRectangle.Top = 0;
1130 UpdateRectangle.Right = Resolution.X;
1131 UpdateRectangle.Bottom = Resolution.Y;
1132
1133 /* Reset the mode change flag */
1134 ModeChanged = FALSE;
1135 }
1136
1137 static VOID VgaUpdateFramebuffer(VOID)
1138 {
1139 SHORT i, j, k;
1140 COORD Resolution = VgaGetDisplayResolution();
1141 DWORD AddressSize = VgaGetAddressSize();
1142 DWORD Address = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG],
1143 VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG]);
1144 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1145
1146 /*
1147 * If console framebuffer is NULL, that means something went wrong
1148 * earlier and this is the final display refresh.
1149 */
1150 if (ConsoleFramebuffer == NULL) return;
1151
1152 /* Check if this is text mode or graphics mode */
1153 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1154 {
1155 /* Graphics mode */
1156 PBYTE GraphicsBuffer = (PBYTE)ConsoleFramebuffer;
1157 DWORD InterlaceHighBit = VGA_INTERLACE_HIGH_BIT;
1158
1159 /*
1160 * Synchronize access to the graphics framebuffer
1161 * with the console framebuffer mutex.
1162 */
1163 WaitForSingleObject(ConsoleMutex, INFINITE);
1164
1165 /* Shift the high bit right by 1 in odd/even mode */
1166 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1167 {
1168 InterlaceHighBit >>= 1;
1169 }
1170
1171 /* Loop through the scanlines */
1172 for (i = 0; i < Resolution.Y; i++)
1173 {
1174 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
1175 {
1176 /* Odd-numbered line in interlaced mode - set the high bit */
1177 Address |= InterlaceHighBit;
1178 }
1179
1180 /* Loop through the pixels */
1181 for (j = 0; j < Resolution.X; j++)
1182 {
1183 BYTE PixelData = 0;
1184
1185 /* Check the shifting mode */
1186 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256)
1187 {
1188 /* 4 bits shifted from each plane */
1189
1190 /* Check if this is 16 or 256 color mode */
1191 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1192 {
1193 /* One byte per pixel */
1194 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
1195 + (Address + (j / VGA_NUM_BANKS))
1196 * AddressSize];
1197 }
1198 else
1199 {
1200 /* 4-bits per pixel */
1201
1202 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
1203 + (Address + (j / (VGA_NUM_BANKS * 2)))
1204 * AddressSize];
1205
1206 /* Check if we should use the highest 4 bits or lowest 4 */
1207 if (((j / VGA_NUM_BANKS) % 2) == 0)
1208 {
1209 /* Highest 4 */
1210 PixelData >>= 4;
1211 }
1212 else
1213 {
1214 /* Lowest 4 */
1215 PixelData &= 0x0F;
1216 }
1217 }
1218 }
1219 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG)
1220 {
1221 /* Check if this is 16 or 256 color mode */
1222 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1223 {
1224 // TODO: NOT IMPLEMENTED
1225 DPRINT1("8-bit interleaved mode is not implemented!\n");
1226 }
1227 else
1228 {
1229 /*
1230 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1231 * then 2 bits shifted from plane 1 and 3 for the next 4
1232 */
1233 DWORD BankNumber = (j / 4) % 2;
1234 DWORD Offset = Address + (j / 8);
1235 BYTE LowPlaneData = VgaMemory[BankNumber * VGA_BANK_SIZE + Offset * AddressSize];
1236 BYTE HighPlaneData = VgaMemory[(BankNumber + 2) * VGA_BANK_SIZE + Offset * AddressSize];
1237
1238 /* Extract the two bits from each plane */
1239 LowPlaneData = (LowPlaneData >> (6 - ((j % 4) * 2))) & 3;
1240 HighPlaneData = (HighPlaneData >> (6 - ((j % 4) * 2))) & 3;
1241
1242 /* Combine them into the pixel */
1243 PixelData = LowPlaneData | (HighPlaneData << 2);
1244 }
1245 }
1246 else
1247 {
1248 /* 1 bit shifted from each plane */
1249
1250 /* Check if this is 16 or 256 color mode */
1251 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1252 {
1253 /* 8 bits per pixel, 2 on each plane */
1254
1255 for (k = 0; k < VGA_NUM_BANKS; k++)
1256 {
1257 /* The data is on plane k, 4 pixels per byte */
1258 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
1259 + (Address + (j / VGA_NUM_BANKS))
1260 * AddressSize];
1261
1262 /* The mask of the first bit in the pair */
1263 BYTE BitMask = 1 << (((3 - (j % VGA_NUM_BANKS)) * 2) + 1);
1264
1265 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1266 if (PlaneData & BitMask) PixelData |= 1 << k;
1267
1268 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1269 if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4);
1270 }
1271 }
1272 else
1273 {
1274 /* 4 bits per pixel, 1 on each plane */
1275
1276 for (k = 0; k < VGA_NUM_BANKS; k++)
1277 {
1278 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
1279 + (Address + (j / (VGA_NUM_BANKS * 2)))
1280 * AddressSize];
1281
1282 /* If the bit on that plane is set, set it */
1283 if (PlaneData & (1 << (7 - (j % 8)))) PixelData |= 1 << k;
1284 }
1285 }
1286 }
1287
1288 if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT))
1289 {
1290 /*
1291 * In 16 color mode, the value is an index to the AC registers
1292 * if external palette access is disabled, otherwise (in case
1293 * of palette loading) it is a blank pixel.
1294 */
1295 PixelData = (VgaAcPalDisable ? VgaAcRegisters[PixelData & 0x0F]
1296 : 0);
1297 }
1298
1299 /* Take into account DoubleVision mode when checking for pixel updates */
1300 if (DoubleVision)
1301 {
1302 /* Now check if the resulting pixel data has changed */
1303 if (GraphicsBuffer[(i * Resolution.X * 4) + (j * 2)] != PixelData)
1304 {
1305 /* Yes, write the new value */
1306 GraphicsBuffer[(i * Resolution.X * 4) + (j * 2)] = PixelData;
1307 GraphicsBuffer[(i * Resolution.X * 4) + (j * 2 + 1)] = PixelData;
1308 GraphicsBuffer[((i * 2 + 1) * Resolution.X * 2) + (j * 2)] = PixelData;
1309 GraphicsBuffer[((i * 2 + 1) * Resolution.X * 2) + (j * 2 + 1)] = PixelData;
1310
1311 /* Mark the specified pixel as changed */
1312 VgaMarkForUpdate(i, j);
1313 }
1314 }
1315 else
1316 {
1317 /* Now check if the resulting pixel data has changed */
1318 if (GraphicsBuffer[i * Resolution.X + j] != PixelData)
1319 {
1320 /* Yes, write the new value */
1321 GraphicsBuffer[i * Resolution.X + j] = PixelData;
1322
1323 /* Mark the specified pixel as changed */
1324 VgaMarkForUpdate(i, j);
1325 }
1326 }
1327 }
1328
1329 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
1330 {
1331 /* Clear the high bit */
1332 Address &= ~InterlaceHighBit;
1333 }
1334
1335 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) || (i & 1))
1336 {
1337 /* Move to the next scanline */
1338 Address += ScanlineSize;
1339 }
1340 }
1341
1342 /*
1343 * Release the console framebuffer mutex
1344 * so that we allow for repainting.
1345 */
1346 ReleaseMutex(ConsoleMutex);
1347 }
1348 else
1349 {
1350 /* Text mode */
1351 DWORD CurrentAddr;
1352 PCHAR_CELL CharBuffer = (PCHAR_CELL)ConsoleFramebuffer;
1353 CHAR_CELL CharInfo;
1354
1355 /* Loop through the scanlines */
1356 for (i = 0; i < Resolution.Y; i++)
1357 {
1358 /* Loop through the characters */
1359 for (j = 0; j < Resolution.X; j++)
1360 {
1361 CurrentAddr = LOWORD((Address + j) * AddressSize);
1362
1363 /* Plane 0 holds the character itself */
1364 CharInfo.Char = VgaMemory[CurrentAddr];
1365
1366 /* Plane 1 holds the attribute */
1367 CharInfo.Attributes = VgaMemory[CurrentAddr + VGA_BANK_SIZE];
1368
1369 /* Now check if the resulting character data has changed */
1370 if ((CharBuffer[i * Resolution.X + j].Char != CharInfo.Char) ||
1371 (CharBuffer[i * Resolution.X + j].Attributes != CharInfo.Attributes))
1372 {
1373 /* Yes, write the new value */
1374 CharBuffer[i * Resolution.X + j] = CharInfo;
1375
1376 /* Mark the specified cell as changed */
1377 VgaMarkForUpdate(i, j);
1378 }
1379 }
1380
1381 /* Move to the next scanline */
1382 Address += ScanlineSize;
1383 }
1384 }
1385 }
1386
1387 static VOID VgaUpdateTextCursor(VOID)
1388 {
1389 COORD Position;
1390 CONSOLE_CURSOR_INFO CursorInfo;
1391 BYTE CursorStart = VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x3F;
1392 BYTE CursorEnd = VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] & 0x1F;
1393 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1394 BYTE TextSize = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1395 WORD Location = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG],
1396 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG]);
1397
1398 /* Just return if we are not in text mode */
1399 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) return;
1400
1401 if (CursorStart < CursorEnd)
1402 {
1403 /* Visible cursor */
1404 CursorInfo.bVisible = TRUE;
1405 CursorInfo.dwSize = (100 * (CursorEnd - CursorStart)) / TextSize;
1406 }
1407 else
1408 {
1409 /* No cursor */
1410 CursorInfo.bVisible = FALSE;
1411 CursorInfo.dwSize = 0;
1412 }
1413
1414 /* Add the cursor skew to the location */
1415 Location += (VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] >> 5) & 3;
1416
1417 /* Find the coordinates of the new position */
1418 Position.X = (SHORT)(Location % ScanlineSize);
1419 Position.Y = (SHORT)(Location / ScanlineSize);
1420
1421 DPRINT1("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position.X, Position.Y);
1422
1423 /* Update the physical cursor */
1424 SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
1425 SetConsoleCursorPosition(TextConsoleBuffer, Position);
1426
1427 /* Reset the cursor move flag */
1428 CursorMoved = FALSE;
1429 }
1430
1431 static BYTE WINAPI VgaReadPort(ULONG Port)
1432 {
1433 DPRINT("VgaReadPort: Port 0x%X\n", Port);
1434
1435 switch (Port)
1436 {
1437 case VGA_MISC_READ:
1438 return VgaMiscRegister;
1439
1440 case VGA_INSTAT0_READ:
1441 return 0; // Not implemented
1442
1443 case VGA_INSTAT1_READ_MONO:
1444 case VGA_INSTAT1_READ_COLOR:
1445 {
1446 BYTE Result = 0;
1447
1448 /* Reset the AC latch */
1449 VgaAcLatch = FALSE;
1450
1451 /* Set a flag if there is a vertical or horizontal retrace */
1452 if (InVerticalRetrace || InHorizontalRetrace) Result |= VGA_STAT_DD;
1453
1454 /* Set an additional flag if there was a vertical retrace */
1455 if (InVerticalRetrace) Result |= VGA_STAT_VRETRACE;
1456
1457 /* Clear the flags */
1458 InHorizontalRetrace = InVerticalRetrace = FALSE;
1459
1460 return Result;
1461 }
1462
1463 case VGA_FEATURE_READ:
1464 return VgaFeatureRegister;
1465
1466 case VGA_AC_INDEX:
1467 return VgaAcIndex;
1468
1469 case VGA_AC_READ:
1470 return VgaAcRegisters[VgaAcIndex];
1471
1472 case VGA_SEQ_INDEX:
1473 return VgaSeqIndex;
1474
1475 case VGA_SEQ_DATA:
1476 return VgaSeqRegisters[VgaSeqIndex];
1477
1478 case VGA_DAC_MASK:
1479 return VgaDacMask;
1480
1481 case VGA_DAC_READ_INDEX:
1482 /* This returns the read/write state */
1483 return (VgaDacReadWrite ? 0 : 3);
1484
1485 case VGA_DAC_WRITE_INDEX:
1486 return (VgaDacIndex / 3);
1487
1488 case VGA_DAC_DATA:
1489 {
1490 /* Ignore reads in write mode */
1491 if (!VgaDacReadWrite)
1492 {
1493 BYTE Data = VgaDacRegisters[VgaDacIndex++];
1494 VgaDacIndex %= VGA_PALETTE_SIZE;
1495 return Data;
1496 }
1497
1498 break;
1499 }
1500
1501 case VGA_CRTC_INDEX_MONO:
1502 case VGA_CRTC_INDEX_COLOR:
1503 return VgaCrtcIndex;
1504
1505 case VGA_CRTC_DATA_MONO:
1506 case VGA_CRTC_DATA_COLOR:
1507 return VgaCrtcRegisters[VgaCrtcIndex];
1508
1509 case VGA_GC_INDEX:
1510 return VgaGcIndex;
1511
1512 case VGA_GC_DATA:
1513 return VgaGcRegisters[VgaGcIndex];
1514
1515 default:
1516 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port);
1517 break;
1518 }
1519
1520 return 0;
1521 }
1522
1523 static VOID WINAPI VgaWritePort(ULONG Port, BYTE Data)
1524 {
1525 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port, Data);
1526
1527 switch (Port)
1528 {
1529 case VGA_MISC_WRITE:
1530 {
1531 VgaMiscRegister = Data;
1532
1533 if (VgaMiscRegister & 0x01)
1534 {
1535 /* Color emulation */
1536 DPRINT1("Color emulation\n");
1537
1538 /* Register the new I/O Ports */
1539 RegisterIoPort(0x3D4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_COLOR
1540 RegisterIoPort(0x3D5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_COLOR
1541 RegisterIoPort(0x3DA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1542
1543 /* Unregister the old ones */
1544 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1545 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1546 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1547 }
1548 else
1549 {
1550 /* Monochrome emulation */
1551 DPRINT1("Monochrome emulation\n");
1552
1553 /* Register the new I/O Ports */
1554 RegisterIoPort(0x3B4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_MONO
1555 RegisterIoPort(0x3B5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_MONO
1556 RegisterIoPort(0x3BA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1557
1558 /* Unregister the old ones */
1559 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1560 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1561 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1562 }
1563
1564 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1565 break;
1566 }
1567
1568 case VGA_FEATURE_WRITE_MONO:
1569 case VGA_FEATURE_WRITE_COLOR:
1570 {
1571 VgaFeatureRegister = Data;
1572 break;
1573 }
1574
1575 case VGA_AC_INDEX:
1576 // case VGA_AC_WRITE:
1577 {
1578 if (!VgaAcLatch)
1579 {
1580 /* Change the index */
1581 BYTE Index = Data & 0x1F;
1582 if (Index < VGA_AC_MAX_REG) VgaAcIndex = Index;
1583
1584 /*
1585 * Change palette protection by checking for
1586 * the Palette Address Source bit.
1587 */
1588 VgaAcPalDisable = (Data & 0x20) ? TRUE : FALSE;
1589 }
1590 else
1591 {
1592 /* Write the data */
1593 VgaWriteAc(Data);
1594 }
1595
1596 /* Toggle the latch */
1597 VgaAcLatch = !VgaAcLatch;
1598 break;
1599 }
1600
1601 case VGA_SEQ_INDEX:
1602 {
1603 /* Set the sequencer index register */
1604 if (Data < VGA_SEQ_MAX_REG) VgaSeqIndex = Data;
1605 break;
1606 }
1607
1608 case VGA_SEQ_DATA:
1609 {
1610 /* Call the sequencer function */
1611 VgaWriteSequencer(Data);
1612 break;
1613 }
1614
1615 case VGA_DAC_MASK:
1616 {
1617 VgaDacMask = Data;
1618 break;
1619 }
1620
1621 case VGA_DAC_READ_INDEX:
1622 {
1623 VgaDacReadWrite = FALSE;
1624 VgaDacIndex = Data * 3;
1625 break;
1626 }
1627
1628 case VGA_DAC_WRITE_INDEX:
1629 {
1630 VgaDacReadWrite = TRUE;
1631 VgaDacIndex = Data * 3;
1632 break;
1633 }
1634
1635 case VGA_DAC_DATA:
1636 {
1637 /* Ignore writes in read mode */
1638 if (VgaDacReadWrite) VgaWriteDac(Data & 0x3F);
1639 break;
1640 }
1641
1642 case VGA_CRTC_INDEX_MONO:
1643 case VGA_CRTC_INDEX_COLOR:
1644 {
1645 /* Set the CRTC index register */
1646 if (Data < VGA_CRTC_MAX_REG) VgaCrtcIndex = Data;
1647 break;
1648 }
1649
1650 case VGA_CRTC_DATA_MONO:
1651 case VGA_CRTC_DATA_COLOR:
1652 {
1653 /* Call the CRTC function */
1654 VgaWriteCrtc(Data);
1655 break;
1656 }
1657
1658 case VGA_GC_INDEX:
1659 {
1660 /* Set the GC index register */
1661 if (Data < VGA_GC_MAX_REG) VgaGcIndex = Data;
1662 break;
1663 }
1664
1665 case VGA_GC_DATA:
1666 {
1667 /* Call the GC function */
1668 VgaWriteGc(Data);
1669 break;
1670 }
1671
1672 default:
1673 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port);
1674 break;
1675 }
1676 }
1677
1678 /* PUBLIC FUNCTIONS ***********************************************************/
1679
1680 DWORD VgaGetVideoBaseAddress(VOID)
1681 {
1682 return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
1683 }
1684
1685 DWORD VgaGetVideoLimitAddress(VOID)
1686 {
1687 return MemoryLimit[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
1688 }
1689
1690 COORD VgaGetDisplayResolution(VOID)
1691 {
1692 COORD Resolution;
1693 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1694
1695 /* The low 8 bits are in the display registers */
1696 Resolution.X = VgaCrtcRegisters[VGA_CRTC_END_HORZ_DISP_REG];
1697 Resolution.Y = VgaCrtcRegisters[VGA_CRTC_VERT_DISP_END_REG];
1698
1699 /* Set the top bits from the overflow register */
1700 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
1701 {
1702 Resolution.Y |= 1 << 8;
1703 }
1704 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
1705 {
1706 Resolution.Y |= 1 << 9;
1707 }
1708
1709 /* Increase the values by 1 */
1710 Resolution.X++;
1711 Resolution.Y++;
1712
1713 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1714 {
1715 /* Multiply the horizontal resolution by the 9/8 dot mode */
1716 Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
1717 ? 8 : 9;
1718
1719 /* The horizontal resolution is halved in 8-bit mode */
1720 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
1721 }
1722
1723 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
1724 {
1725 /* Halve the vertical resolution */
1726 Resolution.Y >>= 1;
1727 }
1728 else
1729 {
1730 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1731 Resolution.Y /= MaximumScanLine;
1732 }
1733
1734 /* Return the resolution */
1735 return Resolution;
1736 }
1737
1738 VOID VgaRefreshDisplay(VOID)
1739 {
1740 HANDLE ConsoleBufferHandle = NULL;
1741 COORD Resolution;
1742
1743 /* Set the vertical retrace flag */
1744 InVerticalRetrace = TRUE;
1745
1746 /* If nothing has changed, just return */
1747 // if (!ModeChanged && !CursorMoved && !PaletteChanged && !NeedsUpdate)
1748 // return;
1749
1750 /* Change the display mode */
1751 if (ModeChanged) VgaChangeMode();
1752
1753 /* Change the text cursor location */
1754 if (CursorMoved) VgaUpdateTextCursor();
1755
1756 /* Retrieve the current resolution */
1757 Resolution = VgaGetDisplayResolution();
1758
1759 if (PaletteChanged)
1760 {
1761 /* Trigger a full update of the screen */
1762 NeedsUpdate = TRUE;
1763 UpdateRectangle.Left = 0;
1764 UpdateRectangle.Top = 0;
1765 UpdateRectangle.Right = Resolution.X;
1766 UpdateRectangle.Bottom = Resolution.Y;
1767
1768 PaletteChanged = FALSE;
1769 }
1770
1771 /* Update the contents of the framebuffer */
1772 VgaUpdateFramebuffer();
1773
1774 /* Ignore if there's nothing to update */
1775 if (!NeedsUpdate) return;
1776
1777 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1778 UpdateRectangle.Left,
1779 UpdateRectangle.Top,
1780 UpdateRectangle.Right,
1781 UpdateRectangle.Bottom);
1782
1783 /* Check if this is text mode or graphics mode */
1784 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1785 {
1786 /* Graphics mode */
1787 ConsoleBufferHandle = GraphicsConsoleBuffer;
1788
1789 /* In DoubleVision mode, scale the update rectangle */
1790 if (DoubleVision)
1791 {
1792 UpdateRectangle.Left *= 2;
1793 UpdateRectangle.Top *= 2;
1794 UpdateRectangle.Right = UpdateRectangle.Right * 2 + 1;
1795 UpdateRectangle.Bottom = UpdateRectangle.Bottom * 2 + 1;
1796 }
1797 }
1798 else
1799 {
1800 /* Text mode */
1801 ConsoleBufferHandle = TextConsoleBuffer;
1802 }
1803
1804 /* Redraw the screen */
1805 __InvalidateConsoleDIBits(ConsoleBufferHandle, &UpdateRectangle);
1806
1807 /* Clear the update flag */
1808 NeedsUpdate = FALSE;
1809 }
1810
1811 VOID VgaHorizontalRetrace(VOID)
1812 {
1813 /* Set the flag */
1814 InHorizontalRetrace = TRUE;
1815 }
1816
1817 VOID VgaReadMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
1818 {
1819 DWORD i;
1820 DWORD VideoAddress;
1821
1822 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
1823
1824 /* Ignore if video RAM access is disabled */
1825 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1826
1827 /* Loop through each byte */
1828 for (i = 0; i < Size; i++)
1829 {
1830 VideoAddress = VgaTranslateReadAddress(Address + i);
1831
1832 /* Load the latch registers */
1833 VgaLatchRegisters[0] = VgaMemory[LOWORD(VideoAddress)];
1834 VgaLatchRegisters[1] = VgaMemory[VGA_BANK_SIZE + LOWORD(VideoAddress)];
1835 VgaLatchRegisters[2] = VgaMemory[(2 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1836 VgaLatchRegisters[3] = VgaMemory[(3 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1837
1838 /* Copy the value to the buffer */
1839 Buffer[i] = VgaMemory[VideoAddress];
1840 }
1841 }
1842
1843 VOID VgaWriteMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
1844 {
1845 DWORD i, j;
1846 DWORD VideoAddress;
1847
1848 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
1849
1850 /* Ignore if video RAM access is disabled */
1851 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1852
1853 /* Also ignore if write access to all planes is disabled */
1854 if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return;
1855
1856 /* Loop through each byte */
1857 for (i = 0; i < Size; i++)
1858 {
1859 VideoAddress = VgaTranslateWriteAddress(Address + i);
1860
1861 for (j = 0; j < VGA_NUM_BANKS; j++)
1862 {
1863 /* Make sure the page is writeable */
1864 if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue;
1865
1866 /* Check if this is chain-4 mode */
1867 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
1868 {
1869 if (((Address + i) & 3) != j)
1870 {
1871 /* This plane will not be accessed */
1872 continue;
1873 }
1874 }
1875
1876 /* Check if this is odd-even mode */
1877 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1878 {
1879 if (((Address + i) & 1) != (j & 1))
1880 {
1881 /* This plane will not be accessed */
1882 continue;
1883 }
1884 }
1885
1886 /* Copy the value to the VGA memory */
1887 VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(Buffer[i], j);
1888 }
1889 }
1890 }
1891
1892 VOID VgaClearMemory(VOID)
1893 {
1894 ZeroMemory(VgaMemory, sizeof(VgaMemory));
1895 }
1896
1897 VOID VgaResetPalette(VOID)
1898 {
1899 PALETTEENTRY Entries[VGA_MAX_COLORS];
1900
1901 /* Restore the default palette */
1902 VgaRestoreDefaultPalette(Entries, VGA_MAX_COLORS);
1903 SetPaletteEntries(PaletteHandle, 0, VGA_MAX_COLORS, Entries);
1904 PaletteChanged = TRUE;
1905 }
1906
1907
1908
1909
1910 BOOL VgaAttachToConsole(VOID)
1911 {
1912 //
1913 // FIXME: We should go back to the saved screen state
1914 //
1915 if (TextResolution.X == 0 || TextResolution.Y == 0)
1916 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
1917
1918 if (TextResolution.X == 0) TextResolution.X = 80;
1919 if (TextResolution.Y == 0) TextResolution.Y = 25;
1920
1921 return VgaAttachToConsoleInternal(&TextResolution);
1922 }
1923
1924 VOID VgaDetachFromConsole(BOOL ChangingMode)
1925 {
1926 ULONG dummyLength;
1927 PVOID dummyPtr;
1928 COORD dummySize = {0};
1929
1930 //
1931 // FIXME: We should save the screen state
1932 //
1933
1934 __RegisterConsoleVDM(0,
1935 NULL,
1936 NULL,
1937 NULL,
1938 0,
1939 &dummyLength,
1940 &dummyPtr,
1941 NULL,
1942 0,
1943 dummySize,
1944 &dummyPtr);
1945
1946 TextFramebuffer = NULL;
1947
1948 if (!ChangingMode)
1949 {
1950 SMALL_RECT ConRect;
1951
1952 /* Restore the old screen buffer */
1953 SetConsoleActiveScreenBuffer(TextConsoleBuffer);
1954
1955 /* Restore the original console size */
1956 ConRect.Left = 0;
1957 ConRect.Top = 0;
1958 ConRect.Right = ConRect.Left + OrgConsoleBufferInfo.srWindow.Right - OrgConsoleBufferInfo.srWindow.Left;
1959 ConRect.Bottom = ConRect.Top + OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top ;
1960 /*
1961 * See the following trick explanation in VgaAttachToConsoleInternal.
1962 */
1963 SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
1964 SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
1965 SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
1966
1967 /* Restore the original cursor shape */
1968 SetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo);
1969 }
1970 }
1971
1972 BOOLEAN VgaInitialize(HANDLE TextHandle)
1973 {
1974 /* Save the default text-mode console output handle */
1975 if (!IsConsoleHandle(TextHandle)) return FALSE;
1976 TextConsoleBuffer = TextHandle;
1977
1978 /* Save the original cursor and console screen buffer information */
1979 if (!GetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo) ||
1980 !GetConsoleScreenBufferInfo(TextConsoleBuffer, &OrgConsoleBufferInfo))
1981 {
1982 return FALSE;
1983 }
1984 ConsoleInfo = OrgConsoleBufferInfo;
1985
1986 /* Initialize the VGA palette and fail if it isn't successfully created */
1987 if (!VgaInitializePalette()) return FALSE;
1988 /***/ VgaResetPalette(); /***/
1989
1990 /* Switch to the text buffer */
1991 SetConsoleActiveScreenBuffer(TextConsoleBuffer);
1992
1993 /* Clear the VGA memory */
1994 VgaClearMemory();
1995
1996 /* Register the I/O Ports */
1997 RegisterIoPort(0x3CC, VgaReadPort, NULL); // VGA_MISC_READ
1998 RegisterIoPort(0x3C2, VgaReadPort, VgaWritePort); // VGA_MISC_WRITE, VGA_INSTAT0_READ
1999 RegisterIoPort(0x3CA, VgaReadPort, NULL); // VGA_FEATURE_READ
2000 RegisterIoPort(0x3C0, VgaReadPort, VgaWritePort); // VGA_AC_INDEX, VGA_AC_WRITE
2001 RegisterIoPort(0x3C1, VgaReadPort, NULL); // VGA_AC_READ
2002 RegisterIoPort(0x3C4, VgaReadPort, VgaWritePort); // VGA_SEQ_INDEX
2003 RegisterIoPort(0x3C5, VgaReadPort, VgaWritePort); // VGA_SEQ_DATA
2004 RegisterIoPort(0x3C6, VgaReadPort, VgaWritePort); // VGA_DAC_MASK
2005 RegisterIoPort(0x3C7, VgaReadPort, VgaWritePort); // VGA_DAC_READ_INDEX
2006 RegisterIoPort(0x3C8, VgaReadPort, VgaWritePort); // VGA_DAC_WRITE_INDEX
2007 RegisterIoPort(0x3C9, VgaReadPort, VgaWritePort); // VGA_DAC_DATA
2008 RegisterIoPort(0x3CE, VgaReadPort, VgaWritePort); // VGA_GC_INDEX
2009 RegisterIoPort(0x3CF, VgaReadPort, VgaWritePort); // VGA_GC_DATA
2010
2011 /* Return success */
2012 return TRUE;
2013 }
2014
2015 VOID VgaCleanup(VOID)
2016 {
2017 if (ScreenMode == GRAPHICS_MODE)
2018 {
2019 /* Leave the current graphics mode */
2020 VgaLeaveGraphicsMode();
2021 }
2022 else
2023 {
2024 /* Leave the current text mode */
2025 VgaLeaveTextMode();
2026 }
2027
2028 VgaDetachFromConsole(FALSE);
2029
2030 CloseHandle(AnotherEvent);
2031 CloseHandle(EndEvent);
2032 CloseHandle(StartEvent);
2033 }
2034
2035 /* EOF */