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