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