3dc376d85177f500236db74d68f974a5aecb24dd
[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 VOID VgaSetActiveScreenBuffer(HANDLE ScreenBuffer)
946 {
947 /* Set the active buffer */
948 SetConsoleActiveScreenBuffer(ScreenBuffer);
949
950 /* Reinitialize the VDM menu */
951 DestroyVdmMenu();
952 CreateVdmMenu(ScreenBuffer);
953 }
954
955 static BOOL VgaEnterGraphicsMode(PCOORD Resolution)
956 {
957 DWORD i;
958 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo;
959 BYTE BitmapInfoBuffer[VGA_BITMAP_INFO_SIZE];
960 LPBITMAPINFO BitmapInfo = (LPBITMAPINFO)BitmapInfoBuffer;
961 LPWORD PaletteIndex = (LPWORD)(BitmapInfo->bmiColors);
962
963 LONG Width = Resolution->X;
964 LONG Height = Resolution->Y;
965
966 /* Use DoubleVision mode if the resolution is too small */
967 if (Width < VGA_MINIMUM_WIDTH && Height < VGA_MINIMUM_HEIGHT)
968 {
969 DoubleVision = TRUE;
970 Width *= 2;
971 Height *= 2;
972 }
973 else
974 {
975 DoubleVision = FALSE;
976 }
977
978 /* Fill the bitmap info header */
979 ZeroMemory(&BitmapInfo->bmiHeader, sizeof(BITMAPINFOHEADER));
980 BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
981 BitmapInfo->bmiHeader.biWidth = Width;
982 BitmapInfo->bmiHeader.biHeight = Height;
983 BitmapInfo->bmiHeader.biBitCount = 8;
984 BitmapInfo->bmiHeader.biPlanes = 1;
985 BitmapInfo->bmiHeader.biCompression = BI_RGB;
986 BitmapInfo->bmiHeader.biSizeImage = Width * Height /* * 1 == biBitCount / 8 */;
987
988 /* Fill the palette data */
989 for (i = 0; i < (VGA_PALETTE_SIZE / 3); i++) PaletteIndex[i] = (WORD)i;
990
991 /* Fill the console graphics buffer info */
992 GraphicsBufferInfo.dwBitMapInfoLength = VGA_BITMAP_INFO_SIZE;
993 GraphicsBufferInfo.lpBitMapInfo = BitmapInfo;
994 GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS;
995
996 /* Create the buffer */
997 GraphicsConsoleBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
998 FILE_SHARE_READ | FILE_SHARE_WRITE,
999 NULL,
1000 CONSOLE_GRAPHICS_BUFFER,
1001 &GraphicsBufferInfo);
1002 if (GraphicsConsoleBuffer == INVALID_HANDLE_VALUE) return FALSE;
1003
1004 /* Save the framebuffer address and mutex */
1005 ConsoleFramebuffer = GraphicsBufferInfo.lpBitMap;
1006 ConsoleMutex = GraphicsBufferInfo.hMutex;
1007
1008 /* Clear the framebuffer */
1009 ZeroMemory(ConsoleFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
1010
1011 /* Set the active buffer */
1012 VgaSetActiveScreenBuffer(GraphicsConsoleBuffer);
1013
1014 /* Set the graphics mode palette */
1015 SetConsolePalette(GraphicsConsoleBuffer,
1016 PaletteHandle,
1017 SYSPAL_NOSTATIC256);
1018
1019 /* Set the screen mode flag */
1020 ScreenMode = GRAPHICS_MODE;
1021
1022 return TRUE;
1023 }
1024
1025 static VOID VgaLeaveGraphicsMode(VOID)
1026 {
1027 /* Release the console framebuffer mutex */
1028 ReleaseMutex(ConsoleMutex);
1029
1030 /* Switch back to the default console text buffer */
1031 // VgaSetActiveScreenBuffer(TextConsoleBuffer);
1032
1033 /* Cleanup the video data */
1034 CloseHandle(ConsoleMutex);
1035 ConsoleMutex = NULL;
1036 ConsoleFramebuffer = NULL;
1037 CloseHandle(GraphicsConsoleBuffer);
1038 GraphicsConsoleBuffer = NULL;
1039 DoubleVision = FALSE;
1040 }
1041
1042 static BOOL VgaEnterTextMode(PCOORD Resolution)
1043 {
1044 DPRINT1("VgaEnterTextMode\n");
1045
1046 /* Switch to the text buffer */
1047 VgaSetActiveScreenBuffer(TextConsoleBuffer);
1048
1049 /* Adjust the text framebuffer if we changed the resolution */
1050 if (TextResolution.X != Resolution->X ||
1051 TextResolution.Y != Resolution->Y)
1052 {
1053 VgaDetachFromConsole(TRUE);
1054
1055 /*
1056 * VgaAttachToConsoleInternal sets TextResolution to the
1057 * new resolution and updates ConsoleInfo.
1058 */
1059 if (!VgaAttachToConsoleInternal(Resolution))
1060 {
1061 DisplayMessage(L"An unexpected error occurred!\n");
1062 EmulatorTerminate();
1063 return FALSE;
1064 }
1065 }
1066 else
1067 {
1068 VgaUpdateCursorPosition();
1069 }
1070
1071 /* The active framebuffer is now the text framebuffer */
1072 ConsoleFramebuffer = TextFramebuffer;
1073
1074 /*
1075 * Set the text mode palette.
1076 *
1077 * WARNING: This call should fail on Windows (and therefore
1078 * we get the default palette and our external behaviour is
1079 * just like Windows' one), but it should success on ReactOS
1080 * (so that we get console palette changes even for text-mode
1081 * screen-buffers, which is a new feature on ReactOS).
1082 */
1083 SetConsolePalette(TextConsoleBuffer,
1084 TextPaletteHandle,
1085 SYSPAL_NOSTATIC256);
1086
1087 /* Set the screen mode flag */
1088 ScreenMode = TEXT_MODE;
1089
1090 return TRUE;
1091 }
1092
1093 static VOID VgaLeaveTextMode(VOID)
1094 {
1095 /* Reset the active framebuffer */
1096 ConsoleFramebuffer = NULL;
1097 }
1098
1099 static VOID VgaChangeMode(VOID)
1100 {
1101 COORD Resolution = VgaGetDisplayResolution();
1102
1103 if (ScreenMode == GRAPHICS_MODE)
1104 {
1105 /* Leave the current graphics mode */
1106 VgaLeaveGraphicsMode();
1107 }
1108 else
1109 {
1110 /* Leave the current text mode */
1111 VgaLeaveTextMode();
1112 }
1113
1114 /* Check if the new mode is alphanumeric */
1115 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA))
1116 {
1117 /* Enter new text mode */
1118 if (!VgaEnterTextMode(&Resolution))
1119 {
1120 DisplayMessage(L"An unexpected VGA error occurred while switching into text mode.");
1121 EmulatorTerminate();
1122 return;
1123 }
1124 }
1125 else
1126 {
1127 /* Enter graphics mode */
1128 if (!VgaEnterGraphicsMode(&Resolution))
1129 {
1130 DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode.");
1131 EmulatorTerminate();
1132 return;
1133 }
1134 }
1135
1136 /* Trigger a full update of the screen */
1137 NeedsUpdate = TRUE;
1138 UpdateRectangle.Left = 0;
1139 UpdateRectangle.Top = 0;
1140 UpdateRectangle.Right = Resolution.X;
1141 UpdateRectangle.Bottom = Resolution.Y;
1142
1143 /* Reset the mode change flag */
1144 ModeChanged = FALSE;
1145 }
1146
1147 static VOID VgaUpdateFramebuffer(VOID)
1148 {
1149 SHORT i, j, k;
1150 COORD Resolution = VgaGetDisplayResolution();
1151 DWORD AddressSize = VgaGetAddressSize();
1152 DWORD Address = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG],
1153 VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG]);
1154 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1155
1156 /*
1157 * If console framebuffer is NULL, that means something went wrong
1158 * earlier and this is the final display refresh.
1159 */
1160 if (ConsoleFramebuffer == NULL) return;
1161
1162 /* Check if this is text mode or graphics mode */
1163 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1164 {
1165 /* Graphics mode */
1166 PBYTE GraphicsBuffer = (PBYTE)ConsoleFramebuffer;
1167 DWORD InterlaceHighBit = VGA_INTERLACE_HIGH_BIT;
1168
1169 /*
1170 * Synchronize access to the graphics framebuffer
1171 * with the console framebuffer mutex.
1172 */
1173 WaitForSingleObject(ConsoleMutex, INFINITE);
1174
1175 /* Shift the high bit right by 1 in odd/even mode */
1176 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1177 {
1178 InterlaceHighBit >>= 1;
1179 }
1180
1181 /* Loop through the scanlines */
1182 for (i = 0; i < Resolution.Y; i++)
1183 {
1184 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
1185 {
1186 /* Odd-numbered line in interlaced mode - set the high bit */
1187 Address |= InterlaceHighBit;
1188 }
1189
1190 /* Loop through the pixels */
1191 for (j = 0; j < Resolution.X; j++)
1192 {
1193 BYTE PixelData = 0;
1194
1195 /* Check the shifting mode */
1196 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256)
1197 {
1198 /* 4 bits shifted from each plane */
1199
1200 /* Check if this is 16 or 256 color mode */
1201 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1202 {
1203 /* One byte per pixel */
1204 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
1205 + (Address + (j / VGA_NUM_BANKS))
1206 * AddressSize];
1207 }
1208 else
1209 {
1210 /* 4-bits per pixel */
1211
1212 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
1213 + (Address + (j / (VGA_NUM_BANKS * 2)))
1214 * AddressSize];
1215
1216 /* Check if we should use the highest 4 bits or lowest 4 */
1217 if (((j / VGA_NUM_BANKS) % 2) == 0)
1218 {
1219 /* Highest 4 */
1220 PixelData >>= 4;
1221 }
1222 else
1223 {
1224 /* Lowest 4 */
1225 PixelData &= 0x0F;
1226 }
1227 }
1228 }
1229 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG)
1230 {
1231 /* Check if this is 16 or 256 color mode */
1232 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1233 {
1234 // TODO: NOT IMPLEMENTED
1235 DPRINT1("8-bit interleaved mode is not implemented!\n");
1236 }
1237 else
1238 {
1239 /*
1240 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1241 * then 2 bits shifted from plane 1 and 3 for the next 4
1242 */
1243 DWORD BankNumber = (j / 4) % 2;
1244 DWORD Offset = Address + (j / 8);
1245 BYTE LowPlaneData = VgaMemory[BankNumber * VGA_BANK_SIZE + Offset * AddressSize];
1246 BYTE HighPlaneData = VgaMemory[(BankNumber + 2) * VGA_BANK_SIZE + Offset * AddressSize];
1247
1248 /* Extract the two bits from each plane */
1249 LowPlaneData = (LowPlaneData >> (6 - ((j % 4) * 2))) & 3;
1250 HighPlaneData = (HighPlaneData >> (6 - ((j % 4) * 2))) & 3;
1251
1252 /* Combine them into the pixel */
1253 PixelData = LowPlaneData | (HighPlaneData << 2);
1254 }
1255 }
1256 else
1257 {
1258 /* 1 bit shifted from each plane */
1259
1260 /* Check if this is 16 or 256 color mode */
1261 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1262 {
1263 /* 8 bits per pixel, 2 on each plane */
1264
1265 for (k = 0; k < VGA_NUM_BANKS; k++)
1266 {
1267 /* The data is on plane k, 4 pixels per byte */
1268 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
1269 + (Address + (j / VGA_NUM_BANKS))
1270 * AddressSize];
1271
1272 /* The mask of the first bit in the pair */
1273 BYTE BitMask = 1 << (((3 - (j % VGA_NUM_BANKS)) * 2) + 1);
1274
1275 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1276 if (PlaneData & BitMask) PixelData |= 1 << k;
1277
1278 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1279 if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4);
1280 }
1281 }
1282 else
1283 {
1284 /* 4 bits per pixel, 1 on each plane */
1285
1286 for (k = 0; k < VGA_NUM_BANKS; k++)
1287 {
1288 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
1289 + (Address + (j / (VGA_NUM_BANKS * 2)))
1290 * AddressSize];
1291
1292 /* If the bit on that plane is set, set it */
1293 if (PlaneData & (1 << (7 - (j % 8)))) PixelData |= 1 << k;
1294 }
1295 }
1296 }
1297
1298 if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT))
1299 {
1300 /*
1301 * In 16 color mode, the value is an index to the AC registers
1302 * if external palette access is disabled, otherwise (in case
1303 * of palette loading) it is a blank pixel.
1304 */
1305 PixelData = (VgaAcPalDisable ? VgaAcRegisters[PixelData & 0x0F]
1306 : 0);
1307 }
1308
1309 /* Take into account DoubleVision mode when checking for pixel updates */
1310 if (DoubleVision)
1311 {
1312 /* Now check if the resulting pixel data has changed */
1313 if (GraphicsBuffer[(i * Resolution.X * 4) + (j * 2)] != PixelData)
1314 {
1315 /* Yes, write the new value */
1316 GraphicsBuffer[(i * Resolution.X * 4) + (j * 2)] = PixelData;
1317 GraphicsBuffer[(i * Resolution.X * 4) + (j * 2 + 1)] = PixelData;
1318 GraphicsBuffer[((i * 2 + 1) * Resolution.X * 2) + (j * 2)] = PixelData;
1319 GraphicsBuffer[((i * 2 + 1) * Resolution.X * 2) + (j * 2 + 1)] = PixelData;
1320
1321 /* Mark the specified pixel as changed */
1322 VgaMarkForUpdate(i, j);
1323 }
1324 }
1325 else
1326 {
1327 /* Now check if the resulting pixel data has changed */
1328 if (GraphicsBuffer[i * Resolution.X + j] != PixelData)
1329 {
1330 /* Yes, write the new value */
1331 GraphicsBuffer[i * Resolution.X + j] = PixelData;
1332
1333 /* Mark the specified pixel as changed */
1334 VgaMarkForUpdate(i, j);
1335 }
1336 }
1337 }
1338
1339 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
1340 {
1341 /* Clear the high bit */
1342 Address &= ~InterlaceHighBit;
1343 }
1344
1345 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) || (i & 1))
1346 {
1347 /* Move to the next scanline */
1348 Address += ScanlineSize;
1349 }
1350 }
1351
1352 /*
1353 * Release the console framebuffer mutex
1354 * so that we allow for repainting.
1355 */
1356 ReleaseMutex(ConsoleMutex);
1357 }
1358 else
1359 {
1360 /* Text mode */
1361 DWORD CurrentAddr;
1362 PCHAR_CELL CharBuffer = (PCHAR_CELL)ConsoleFramebuffer;
1363 CHAR_CELL CharInfo;
1364
1365 /* Loop through the scanlines */
1366 for (i = 0; i < Resolution.Y; i++)
1367 {
1368 /* Loop through the characters */
1369 for (j = 0; j < Resolution.X; j++)
1370 {
1371 CurrentAddr = LOWORD((Address + j) * AddressSize);
1372
1373 /* Plane 0 holds the character itself */
1374 CharInfo.Char = VgaMemory[CurrentAddr];
1375
1376 /* Plane 1 holds the attribute */
1377 CharInfo.Attributes = VgaMemory[CurrentAddr + VGA_BANK_SIZE];
1378
1379 /* Now check if the resulting character data has changed */
1380 if ((CharBuffer[i * Resolution.X + j].Char != CharInfo.Char) ||
1381 (CharBuffer[i * Resolution.X + j].Attributes != CharInfo.Attributes))
1382 {
1383 /* Yes, write the new value */
1384 CharBuffer[i * Resolution.X + j] = CharInfo;
1385
1386 /* Mark the specified cell as changed */
1387 VgaMarkForUpdate(i, j);
1388 }
1389 }
1390
1391 /* Move to the next scanline */
1392 Address += ScanlineSize;
1393 }
1394 }
1395 }
1396
1397 static VOID VgaUpdateTextCursor(VOID)
1398 {
1399 COORD Position;
1400 CONSOLE_CURSOR_INFO CursorInfo;
1401 BYTE CursorStart = VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x3F;
1402 BYTE CursorEnd = VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] & 0x1F;
1403 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1404 BYTE TextSize = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1405 WORD Location = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG],
1406 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG]);
1407
1408 /* Just return if we are not in text mode */
1409 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) return;
1410
1411 if (CursorStart < CursorEnd)
1412 {
1413 /* Visible cursor */
1414 CursorInfo.bVisible = TRUE;
1415 CursorInfo.dwSize = (100 * (CursorEnd - CursorStart)) / TextSize;
1416 }
1417 else
1418 {
1419 /* No cursor */
1420 CursorInfo.bVisible = FALSE;
1421 CursorInfo.dwSize = 0;
1422 }
1423
1424 /* Add the cursor skew to the location */
1425 Location += (VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] >> 5) & 3;
1426
1427 /* Find the coordinates of the new position */
1428 Position.X = (SHORT)(Location % ScanlineSize);
1429 Position.Y = (SHORT)(Location / ScanlineSize);
1430
1431 DPRINT1("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position.X, Position.Y);
1432
1433 /* Update the physical cursor */
1434 SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
1435 SetConsoleCursorPosition(TextConsoleBuffer, Position);
1436
1437 /* Reset the cursor move flag */
1438 CursorMoved = FALSE;
1439 }
1440
1441 static BYTE WINAPI VgaReadPort(ULONG Port)
1442 {
1443 DPRINT("VgaReadPort: Port 0x%X\n", Port);
1444
1445 switch (Port)
1446 {
1447 case VGA_MISC_READ:
1448 return VgaMiscRegister;
1449
1450 case VGA_INSTAT0_READ:
1451 return 0; // Not implemented
1452
1453 case VGA_INSTAT1_READ_MONO:
1454 case VGA_INSTAT1_READ_COLOR:
1455 {
1456 BYTE Result = 0;
1457
1458 /* Reset the AC latch */
1459 VgaAcLatch = FALSE;
1460
1461 /* Set a flag if there is a vertical or horizontal retrace */
1462 if (InVerticalRetrace || InHorizontalRetrace) Result |= VGA_STAT_DD;
1463
1464 /* Set an additional flag if there was a vertical retrace */
1465 if (InVerticalRetrace) Result |= VGA_STAT_VRETRACE;
1466
1467 /* Clear the flags */
1468 InHorizontalRetrace = InVerticalRetrace = FALSE;
1469
1470 return Result;
1471 }
1472
1473 case VGA_FEATURE_READ:
1474 return VgaFeatureRegister;
1475
1476 case VGA_AC_INDEX:
1477 return VgaAcIndex;
1478
1479 case VGA_AC_READ:
1480 return VgaAcRegisters[VgaAcIndex];
1481
1482 case VGA_SEQ_INDEX:
1483 return VgaSeqIndex;
1484
1485 case VGA_SEQ_DATA:
1486 return VgaSeqRegisters[VgaSeqIndex];
1487
1488 case VGA_DAC_MASK:
1489 return VgaDacMask;
1490
1491 case VGA_DAC_READ_INDEX:
1492 /* This returns the read/write state */
1493 return (VgaDacReadWrite ? 0 : 3);
1494
1495 case VGA_DAC_WRITE_INDEX:
1496 return (VgaDacIndex / 3);
1497
1498 case VGA_DAC_DATA:
1499 {
1500 /* Ignore reads in write mode */
1501 if (!VgaDacReadWrite)
1502 {
1503 BYTE Data = VgaDacRegisters[VgaDacIndex++];
1504 VgaDacIndex %= VGA_PALETTE_SIZE;
1505 return Data;
1506 }
1507
1508 break;
1509 }
1510
1511 case VGA_CRTC_INDEX_MONO:
1512 case VGA_CRTC_INDEX_COLOR:
1513 return VgaCrtcIndex;
1514
1515 case VGA_CRTC_DATA_MONO:
1516 case VGA_CRTC_DATA_COLOR:
1517 return VgaCrtcRegisters[VgaCrtcIndex];
1518
1519 case VGA_GC_INDEX:
1520 return VgaGcIndex;
1521
1522 case VGA_GC_DATA:
1523 return VgaGcRegisters[VgaGcIndex];
1524
1525 default:
1526 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port);
1527 break;
1528 }
1529
1530 return 0;
1531 }
1532
1533 static VOID WINAPI VgaWritePort(ULONG Port, BYTE Data)
1534 {
1535 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port, Data);
1536
1537 switch (Port)
1538 {
1539 case VGA_MISC_WRITE:
1540 {
1541 VgaMiscRegister = Data;
1542
1543 if (VgaMiscRegister & 0x01)
1544 {
1545 /* Color emulation */
1546 DPRINT1("Color emulation\n");
1547
1548 /* Register the new I/O Ports */
1549 RegisterIoPort(0x3D4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_COLOR
1550 RegisterIoPort(0x3D5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_COLOR
1551 RegisterIoPort(0x3DA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1552
1553 /* Unregister the old ones */
1554 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1555 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1556 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1557 }
1558 else
1559 {
1560 /* Monochrome emulation */
1561 DPRINT1("Monochrome emulation\n");
1562
1563 /* Register the new I/O Ports */
1564 RegisterIoPort(0x3B4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_MONO
1565 RegisterIoPort(0x3B5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_MONO
1566 RegisterIoPort(0x3BA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1567
1568 /* Unregister the old ones */
1569 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1570 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1571 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1572 }
1573
1574 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1575 break;
1576 }
1577
1578 case VGA_FEATURE_WRITE_MONO:
1579 case VGA_FEATURE_WRITE_COLOR:
1580 {
1581 VgaFeatureRegister = Data;
1582 break;
1583 }
1584
1585 case VGA_AC_INDEX:
1586 // case VGA_AC_WRITE:
1587 {
1588 if (!VgaAcLatch)
1589 {
1590 /* Change the index */
1591 BYTE Index = Data & 0x1F;
1592 if (Index < VGA_AC_MAX_REG) VgaAcIndex = Index;
1593
1594 /*
1595 * Change palette protection by checking for
1596 * the Palette Address Source bit.
1597 */
1598 VgaAcPalDisable = (Data & 0x20) ? TRUE : FALSE;
1599 }
1600 else
1601 {
1602 /* Write the data */
1603 VgaWriteAc(Data);
1604 }
1605
1606 /* Toggle the latch */
1607 VgaAcLatch = !VgaAcLatch;
1608 break;
1609 }
1610
1611 case VGA_SEQ_INDEX:
1612 {
1613 /* Set the sequencer index register */
1614 if (Data < VGA_SEQ_MAX_REG) VgaSeqIndex = Data;
1615 break;
1616 }
1617
1618 case VGA_SEQ_DATA:
1619 {
1620 /* Call the sequencer function */
1621 VgaWriteSequencer(Data);
1622 break;
1623 }
1624
1625 case VGA_DAC_MASK:
1626 {
1627 VgaDacMask = Data;
1628 break;
1629 }
1630
1631 case VGA_DAC_READ_INDEX:
1632 {
1633 VgaDacReadWrite = FALSE;
1634 VgaDacIndex = Data * 3;
1635 break;
1636 }
1637
1638 case VGA_DAC_WRITE_INDEX:
1639 {
1640 VgaDacReadWrite = TRUE;
1641 VgaDacIndex = Data * 3;
1642 break;
1643 }
1644
1645 case VGA_DAC_DATA:
1646 {
1647 /* Ignore writes in read mode */
1648 if (VgaDacReadWrite) VgaWriteDac(Data & 0x3F);
1649 break;
1650 }
1651
1652 case VGA_CRTC_INDEX_MONO:
1653 case VGA_CRTC_INDEX_COLOR:
1654 {
1655 /* Set the CRTC index register */
1656 if (Data < VGA_CRTC_MAX_REG) VgaCrtcIndex = Data;
1657 break;
1658 }
1659
1660 case VGA_CRTC_DATA_MONO:
1661 case VGA_CRTC_DATA_COLOR:
1662 {
1663 /* Call the CRTC function */
1664 VgaWriteCrtc(Data);
1665 break;
1666 }
1667
1668 case VGA_GC_INDEX:
1669 {
1670 /* Set the GC index register */
1671 if (Data < VGA_GC_MAX_REG) VgaGcIndex = Data;
1672 break;
1673 }
1674
1675 case VGA_GC_DATA:
1676 {
1677 /* Call the GC function */
1678 VgaWriteGc(Data);
1679 break;
1680 }
1681
1682 default:
1683 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port);
1684 break;
1685 }
1686 }
1687
1688 /* PUBLIC FUNCTIONS ***********************************************************/
1689
1690 DWORD VgaGetVideoBaseAddress(VOID)
1691 {
1692 return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
1693 }
1694
1695 DWORD VgaGetVideoLimitAddress(VOID)
1696 {
1697 return MemoryLimit[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
1698 }
1699
1700 COORD VgaGetDisplayResolution(VOID)
1701 {
1702 COORD Resolution;
1703 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1704
1705 /* The low 8 bits are in the display registers */
1706 Resolution.X = VgaCrtcRegisters[VGA_CRTC_END_HORZ_DISP_REG];
1707 Resolution.Y = VgaCrtcRegisters[VGA_CRTC_VERT_DISP_END_REG];
1708
1709 /* Set the top bits from the overflow register */
1710 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
1711 {
1712 Resolution.Y |= 1 << 8;
1713 }
1714 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
1715 {
1716 Resolution.Y |= 1 << 9;
1717 }
1718
1719 /* Increase the values by 1 */
1720 Resolution.X++;
1721 Resolution.Y++;
1722
1723 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1724 {
1725 /* Multiply the horizontal resolution by the 9/8 dot mode */
1726 Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
1727 ? 8 : 9;
1728
1729 /* The horizontal resolution is halved in 8-bit mode */
1730 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
1731 }
1732
1733 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
1734 {
1735 /* Halve the vertical resolution */
1736 Resolution.Y >>= 1;
1737 }
1738 else
1739 {
1740 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1741 Resolution.Y /= MaximumScanLine;
1742 }
1743
1744 /* Return the resolution */
1745 return Resolution;
1746 }
1747
1748 VOID VgaRefreshDisplay(VOID)
1749 {
1750 HANDLE ConsoleBufferHandle = NULL;
1751 COORD Resolution;
1752
1753 /* Set the vertical retrace flag */
1754 InVerticalRetrace = TRUE;
1755
1756 /* If nothing has changed, just return */
1757 // if (!ModeChanged && !CursorMoved && !PaletteChanged && !NeedsUpdate)
1758 // return;
1759
1760 /* Change the display mode */
1761 if (ModeChanged) VgaChangeMode();
1762
1763 /* Change the text cursor location */
1764 if (CursorMoved) VgaUpdateTextCursor();
1765
1766 /* Retrieve the current resolution */
1767 Resolution = VgaGetDisplayResolution();
1768
1769 if (PaletteChanged)
1770 {
1771 /* Trigger a full update of the screen */
1772 NeedsUpdate = TRUE;
1773 UpdateRectangle.Left = 0;
1774 UpdateRectangle.Top = 0;
1775 UpdateRectangle.Right = Resolution.X;
1776 UpdateRectangle.Bottom = Resolution.Y;
1777
1778 PaletteChanged = FALSE;
1779 }
1780
1781 /* Update the contents of the framebuffer */
1782 VgaUpdateFramebuffer();
1783
1784 /* Ignore if there's nothing to update */
1785 if (!NeedsUpdate) return;
1786
1787 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1788 UpdateRectangle.Left,
1789 UpdateRectangle.Top,
1790 UpdateRectangle.Right,
1791 UpdateRectangle.Bottom);
1792
1793 /* Check if this is text mode or graphics mode */
1794 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1795 {
1796 /* Graphics mode */
1797 ConsoleBufferHandle = GraphicsConsoleBuffer;
1798
1799 /* In DoubleVision mode, scale the update rectangle */
1800 if (DoubleVision)
1801 {
1802 UpdateRectangle.Left *= 2;
1803 UpdateRectangle.Top *= 2;
1804 UpdateRectangle.Right = UpdateRectangle.Right * 2 + 1;
1805 UpdateRectangle.Bottom = UpdateRectangle.Bottom * 2 + 1;
1806 }
1807 }
1808 else
1809 {
1810 /* Text mode */
1811 ConsoleBufferHandle = TextConsoleBuffer;
1812 }
1813
1814 /* Redraw the screen */
1815 __InvalidateConsoleDIBits(ConsoleBufferHandle, &UpdateRectangle);
1816
1817 /* Clear the update flag */
1818 NeedsUpdate = FALSE;
1819 }
1820
1821 VOID VgaHorizontalRetrace(VOID)
1822 {
1823 /* Set the flag */
1824 InHorizontalRetrace = TRUE;
1825 }
1826
1827 VOID VgaReadMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
1828 {
1829 DWORD i;
1830 DWORD VideoAddress;
1831
1832 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
1833
1834 /* Ignore if video RAM access is disabled */
1835 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1836
1837 /* Loop through each byte */
1838 for (i = 0; i < Size; i++)
1839 {
1840 VideoAddress = VgaTranslateReadAddress(Address + i);
1841
1842 /* Load the latch registers */
1843 VgaLatchRegisters[0] = VgaMemory[LOWORD(VideoAddress)];
1844 VgaLatchRegisters[1] = VgaMemory[VGA_BANK_SIZE + LOWORD(VideoAddress)];
1845 VgaLatchRegisters[2] = VgaMemory[(2 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1846 VgaLatchRegisters[3] = VgaMemory[(3 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1847
1848 /* Copy the value to the buffer */
1849 Buffer[i] = VgaMemory[VideoAddress];
1850 }
1851 }
1852
1853 VOID VgaWriteMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
1854 {
1855 DWORD i, j;
1856 DWORD VideoAddress;
1857
1858 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
1859
1860 /* Ignore if video RAM access is disabled */
1861 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1862
1863 /* Also ignore if write access to all planes is disabled */
1864 if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return;
1865
1866 /* Loop through each byte */
1867 for (i = 0; i < Size; i++)
1868 {
1869 VideoAddress = VgaTranslateWriteAddress(Address + i);
1870
1871 for (j = 0; j < VGA_NUM_BANKS; j++)
1872 {
1873 /* Make sure the page is writeable */
1874 if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue;
1875
1876 /* Check if this is chain-4 mode */
1877 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
1878 {
1879 if (((Address + i) & 3) != j)
1880 {
1881 /* This plane will not be accessed */
1882 continue;
1883 }
1884 }
1885
1886 /* Check if this is odd-even mode */
1887 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1888 {
1889 if (((Address + i) & 1) != (j & 1))
1890 {
1891 /* This plane will not be accessed */
1892 continue;
1893 }
1894 }
1895
1896 /* Copy the value to the VGA memory */
1897 VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(Buffer[i], j);
1898 }
1899 }
1900 }
1901
1902 VOID VgaClearMemory(VOID)
1903 {
1904 ZeroMemory(VgaMemory, sizeof(VgaMemory));
1905 }
1906
1907 VOID VgaResetPalette(VOID)
1908 {
1909 PALETTEENTRY Entries[VGA_MAX_COLORS];
1910
1911 /* Restore the default palette */
1912 VgaRestoreDefaultPalette(Entries, VGA_MAX_COLORS);
1913 SetPaletteEntries(PaletteHandle, 0, VGA_MAX_COLORS, Entries);
1914 PaletteChanged = TRUE;
1915 }
1916
1917
1918
1919
1920 VOID ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent)
1921 {
1922 DPRINT1("Screen events not handled\n");
1923 }
1924
1925 BOOL VgaAttachToConsole(VOID)
1926 {
1927 //
1928 // FIXME: We should go back to the saved screen state
1929 //
1930 if (TextResolution.X == 0 || TextResolution.Y == 0)
1931 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
1932
1933 if (TextResolution.X == 0) TextResolution.X = 80;
1934 if (TextResolution.Y == 0) TextResolution.Y = 25;
1935
1936 return VgaAttachToConsoleInternal(&TextResolution);
1937 }
1938
1939 VOID VgaDetachFromConsole(BOOL ChangingMode)
1940 {
1941 ULONG dummyLength;
1942 PVOID dummyPtr;
1943 COORD dummySize = {0};
1944
1945 //
1946 // FIXME: We should save the screen state
1947 //
1948
1949 __RegisterConsoleVDM(0,
1950 NULL,
1951 NULL,
1952 NULL,
1953 0,
1954 &dummyLength,
1955 &dummyPtr,
1956 NULL,
1957 0,
1958 dummySize,
1959 &dummyPtr);
1960
1961 TextFramebuffer = NULL;
1962
1963 if (!ChangingMode)
1964 {
1965 SMALL_RECT ConRect;
1966
1967 /* Restore the old screen buffer */
1968 VgaSetActiveScreenBuffer(TextConsoleBuffer);
1969
1970 /* Restore the original console size */
1971 ConRect.Left = 0;
1972 ConRect.Top = 0;
1973 ConRect.Right = ConRect.Left + OrgConsoleBufferInfo.srWindow.Right - OrgConsoleBufferInfo.srWindow.Left;
1974 ConRect.Bottom = ConRect.Top + OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top ;
1975 /*
1976 * See the following trick explanation in VgaAttachToConsoleInternal.
1977 */
1978 SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
1979 SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
1980 SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
1981
1982 /* Restore the original cursor shape */
1983 SetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo);
1984 }
1985 }
1986
1987 BOOLEAN VgaInitialize(HANDLE TextHandle)
1988 {
1989 /* Save the default text-mode console output handle */
1990 if (!IsConsoleHandle(TextHandle)) return FALSE;
1991 TextConsoleBuffer = TextHandle;
1992
1993 /* Save the original cursor and console screen buffer information */
1994 if (!GetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo) ||
1995 !GetConsoleScreenBufferInfo(TextConsoleBuffer, &OrgConsoleBufferInfo))
1996 {
1997 return FALSE;
1998 }
1999 ConsoleInfo = OrgConsoleBufferInfo;
2000
2001 /* Initialize the VGA palette and fail if it isn't successfully created */
2002 if (!VgaInitializePalette()) return FALSE;
2003 /***/ VgaResetPalette(); /***/
2004
2005 /* Switch to the text buffer */
2006 VgaSetActiveScreenBuffer(TextConsoleBuffer);
2007
2008 /* Clear the VGA memory */
2009 VgaClearMemory();
2010
2011 /* Register the I/O Ports */
2012 RegisterIoPort(0x3CC, VgaReadPort, NULL); // VGA_MISC_READ
2013 RegisterIoPort(0x3C2, VgaReadPort, VgaWritePort); // VGA_MISC_WRITE, VGA_INSTAT0_READ
2014 RegisterIoPort(0x3CA, VgaReadPort, NULL); // VGA_FEATURE_READ
2015 RegisterIoPort(0x3C0, VgaReadPort, VgaWritePort); // VGA_AC_INDEX, VGA_AC_WRITE
2016 RegisterIoPort(0x3C1, VgaReadPort, NULL); // VGA_AC_READ
2017 RegisterIoPort(0x3C4, VgaReadPort, VgaWritePort); // VGA_SEQ_INDEX
2018 RegisterIoPort(0x3C5, VgaReadPort, VgaWritePort); // VGA_SEQ_DATA
2019 RegisterIoPort(0x3C6, VgaReadPort, VgaWritePort); // VGA_DAC_MASK
2020 RegisterIoPort(0x3C7, VgaReadPort, VgaWritePort); // VGA_DAC_READ_INDEX
2021 RegisterIoPort(0x3C8, VgaReadPort, VgaWritePort); // VGA_DAC_WRITE_INDEX
2022 RegisterIoPort(0x3C9, VgaReadPort, VgaWritePort); // VGA_DAC_DATA
2023 RegisterIoPort(0x3CE, VgaReadPort, VgaWritePort); // VGA_GC_INDEX
2024 RegisterIoPort(0x3CF, VgaReadPort, VgaWritePort); // VGA_GC_DATA
2025
2026 /* Return success */
2027 return TRUE;
2028 }
2029
2030 VOID VgaCleanup(VOID)
2031 {
2032 if (ScreenMode == GRAPHICS_MODE)
2033 {
2034 /* Leave the current graphics mode */
2035 VgaLeaveGraphicsMode();
2036 }
2037 else
2038 {
2039 /* Leave the current text mode */
2040 VgaLeaveTextMode();
2041 }
2042
2043 VgaDetachFromConsole(FALSE);
2044
2045 CloseHandle(AnotherEvent);
2046 CloseHandle(EndEvent);
2047 CloseHandle(StartEvent);
2048 }
2049
2050 /* EOF */