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