[NTVDM]: Minor code reorganization. StartTickCount is commented out because it's...
[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 >>= 2;
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 /* Multiply the offset by the address size */
647 Offset *= VgaGetAddressSize();
648
649 return Offset + Plane * VGA_BANK_SIZE;
650 }
651
652 static inline DWORD VgaTranslateWriteAddress(DWORD Address)
653 {
654 DWORD Offset = Address - VgaGetVideoBaseAddress();
655
656 /* Check for chain-4 and odd-even mode */
657 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
658 {
659 /* Shift the offset to the right by 2 */
660 Offset >>= 2;
661 }
662 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
663 {
664 /* Shift the offset to the right by 1 */
665 Offset >>= 1;
666 }
667
668 /* Multiply the offset by the address size */
669 Offset *= VgaGetAddressSize();
670
671 /* Return the offset on plane 0 */
672 return Offset;
673 }
674
675 static inline BYTE VgaTranslateByteForWriting(BYTE Data, BYTE Plane)
676 {
677 BYTE WriteMode = VgaGcRegisters[VGA_GC_MODE_REG] & 0x03;
678 BYTE BitMask = VgaGcRegisters[VGA_GC_BITMASK_REG];
679
680 if (WriteMode == 1)
681 {
682 /* In write mode 1 just return the latch register */
683 return VgaLatchRegisters[Plane];
684 }
685
686 if (WriteMode != 2)
687 {
688 /* Write modes 0 and 3 rotate the data to the right first */
689 BYTE RotateCount = VgaGcRegisters[VGA_GC_ROTATE_REG] & 0x07;
690 Data = LOBYTE(((DWORD)Data >> RotateCount) | ((DWORD)Data << (8 - RotateCount)));
691 }
692 else
693 {
694 /* Write mode 2 expands the appropriate bit to all 8 bits */
695 Data = (Data & (1 << Plane)) ? 0xFF : 0x00;
696 }
697
698 if (WriteMode == 0)
699 {
700 /*
701 * In write mode 0, the enable set/reset register decides if the
702 * set/reset bit should be expanded to all 8 bits.
703 */
704 if (VgaGcRegisters[VGA_GC_ENABLE_RESET_REG] & (1 << Plane))
705 {
706 /* Copy the bit from the set/reset register to all 8 bits */
707 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
708 }
709 }
710
711 if (WriteMode != 3)
712 {
713 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
714 BYTE LogicalOperation = (VgaGcRegisters[VGA_GC_ROTATE_REG] >> 3) & 0x03;
715
716 if (LogicalOperation == 1) Data &= VgaLatchRegisters[Plane];
717 else if (LogicalOperation == 2) Data |= VgaLatchRegisters[Plane];
718 else if (LogicalOperation == 3) Data ^= VgaLatchRegisters[Plane];
719 }
720 else
721 {
722 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
723 BitMask &= Data;
724
725 /* Then we expand the bit in the set/reset field */
726 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
727 }
728
729 /* Bits cleared in the bitmask are replaced with latch register bits */
730 Data = (Data & BitMask) | (VgaLatchRegisters[Plane] & (~BitMask));
731
732 /* Return the byte */
733 return Data;
734 }
735
736 static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column)
737 {
738 /* Check if this is the first time the rectangle is updated */
739 if (!NeedsUpdate)
740 {
741 UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT;
742 UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT;
743 }
744
745 /* Expand the rectangle to include the point */
746 UpdateRectangle.Left = min(UpdateRectangle.Left, Column);
747 UpdateRectangle.Right = max(UpdateRectangle.Right, Column);
748 UpdateRectangle.Top = min(UpdateRectangle.Top, Row);
749 UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Row);
750
751 /* Set the update request flag */
752 NeedsUpdate = TRUE;
753 }
754
755 static VOID VgaRestoreDefaultPalette(PPALETTEENTRY Entries, USHORT NumOfEntries)
756 {
757 USHORT i;
758
759 /* Copy the colors of the default palette to the DAC and console palette */
760 for (i = 0; i < NumOfEntries; i++)
761 {
762 /* Set the palette entries */
763 Entries[i].peRed = GetRValue(VgaDefaultPalette[i]);
764 Entries[i].peGreen = GetGValue(VgaDefaultPalette[i]);
765 Entries[i].peBlue = GetBValue(VgaDefaultPalette[i]);
766 Entries[i].peFlags = 0;
767
768 /* Set the DAC registers */
769 VgaDacRegisters[i * 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette[i]));
770 VgaDacRegisters[i * 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette[i]));
771 VgaDacRegisters[i * 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette[i]));
772 }
773 }
774
775 static BOOLEAN VgaInitializePalette(VOID)
776 {
777 INT i;
778 BOOLEAN Result = FALSE;
779 LPLOGPALETTE Palette, TextPalette;
780
781 /* Allocate storage space for the palettes */
782 Palette = (LPLOGPALETTE)HeapAlloc(GetProcessHeap(),
783 HEAP_ZERO_MEMORY,
784 sizeof(LOGPALETTE) +
785 VGA_MAX_COLORS * sizeof(PALETTEENTRY));
786 TextPalette = (LPLOGPALETTE)HeapAlloc(GetProcessHeap(),
787 HEAP_ZERO_MEMORY,
788 sizeof(LOGPALETTE) +
789 (VGA_AC_PAL_F_REG + 1) * sizeof(PALETTEENTRY));
790 if ((Palette == NULL) || (TextPalette == NULL)) goto Cleanup;
791
792 /* Initialize the palettes */
793 Palette->palVersion = TextPalette->palVersion = 0x0300;
794 Palette->palNumEntries = VGA_MAX_COLORS;
795 TextPalette->palNumEntries = VGA_AC_PAL_F_REG + 1;
796
797 /* Restore the default graphics palette */
798 VgaRestoreDefaultPalette(Palette->palPalEntry, Palette->palNumEntries);
799
800 /* Set the default text palette */
801 for (i = 0; i < TextPalette->palNumEntries; i++)
802 {
803 /* Set the palette entries */
804 TextPalette->palPalEntry[i].peRed = GetRValue(ConsoleColors[i]);
805 TextPalette->palPalEntry[i].peGreen = GetGValue(ConsoleColors[i]);
806 TextPalette->palPalEntry[i].peBlue = GetBValue(ConsoleColors[i]);
807 TextPalette->palPalEntry[i].peFlags = 0;
808 }
809
810 /* Create the palettes */
811 PaletteHandle = CreatePalette(Palette);
812 TextPaletteHandle = CreatePalette(TextPalette);
813
814 if (PaletteHandle != NULL && TextPaletteHandle != NULL)
815 {
816 /* The palettes have been created successfully */
817 Result = TRUE;
818 }
819
820 Cleanup:
821 /* Free the palettes */
822 if (Palette) HeapFree(GetProcessHeap(), 0, Palette);
823 if (TextPalette) HeapFree(GetProcessHeap(), 0, TextPalette);
824
825 if (!Result)
826 {
827 /* Something failed, delete the palettes */
828 if (PaletteHandle) DeleteObject(PaletteHandle);
829 if (TextPaletteHandle) DeleteObject(TextPaletteHandle);
830 }
831
832 return Result;
833 }
834
835 static VOID VgaResetPalette(VOID)
836 {
837 PALETTEENTRY Entries[VGA_MAX_COLORS];
838
839 /* Restore the default palette */
840 VgaRestoreDefaultPalette(Entries, VGA_MAX_COLORS);
841 SetPaletteEntries(PaletteHandle, 0, VGA_MAX_COLORS, Entries);
842 PaletteChanged = TRUE;
843 }
844
845 static VOID VgaSetActiveScreenBuffer(HANDLE ScreenBuffer)
846 {
847 /* Set the active buffer */
848 SetConsoleActiveScreenBuffer(ScreenBuffer);
849
850 /* Reinitialize the VDM menu */
851 DestroyVdmMenu();
852 CreateVdmMenu(ScreenBuffer);
853 }
854
855 static BOOL VgaEnterGraphicsMode(PCOORD Resolution)
856 {
857 DWORD i;
858 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo;
859 BYTE BitmapInfoBuffer[VGA_BITMAP_INFO_SIZE];
860 LPBITMAPINFO BitmapInfo = (LPBITMAPINFO)BitmapInfoBuffer;
861 LPWORD PaletteIndex = (LPWORD)(BitmapInfo->bmiColors);
862
863 LONG Width = Resolution->X;
864 LONG Height = Resolution->Y;
865
866 /* Use DoubleVision mode if the resolution is too small */
867 DoubleWidth = (Width < VGA_MINIMUM_WIDTH);
868 if (DoubleWidth) Width *= 2;
869 DoubleHeight = (Height < VGA_MINIMUM_HEIGHT);
870 if (DoubleHeight) Height *= 2;
871
872 /* Fill the bitmap info header */
873 RtlZeroMemory(&BitmapInfo->bmiHeader, sizeof(BitmapInfo->bmiHeader));
874 BitmapInfo->bmiHeader.biSize = sizeof(BitmapInfo->bmiHeader);
875 BitmapInfo->bmiHeader.biWidth = Width;
876 BitmapInfo->bmiHeader.biHeight = Height;
877 BitmapInfo->bmiHeader.biBitCount = 8;
878 BitmapInfo->bmiHeader.biPlanes = 1;
879 BitmapInfo->bmiHeader.biCompression = BI_RGB;
880 BitmapInfo->bmiHeader.biSizeImage = Width * Height /* * 1 == biBitCount / 8 */;
881
882 /* Fill the palette data */
883 for (i = 0; i < (VGA_PALETTE_SIZE / 3); i++) PaletteIndex[i] = (WORD)i;
884
885 /* Fill the console graphics buffer info */
886 GraphicsBufferInfo.dwBitMapInfoLength = VGA_BITMAP_INFO_SIZE;
887 GraphicsBufferInfo.lpBitMapInfo = BitmapInfo;
888 GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS;
889
890 /* Create the buffer */
891 GraphicsConsoleBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
892 FILE_SHARE_READ | FILE_SHARE_WRITE,
893 NULL,
894 CONSOLE_GRAPHICS_BUFFER,
895 &GraphicsBufferInfo);
896 if (GraphicsConsoleBuffer == INVALID_HANDLE_VALUE) return FALSE;
897
898 /* Save the framebuffer address and mutex */
899 ConsoleFramebuffer = GraphicsBufferInfo.lpBitMap;
900 ConsoleMutex = GraphicsBufferInfo.hMutex;
901
902 /* Clear the framebuffer */
903 RtlZeroMemory(ConsoleFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
904
905 /* Set the active buffer */
906 VgaSetActiveScreenBuffer(GraphicsConsoleBuffer);
907
908 /* Set the graphics mode palette */
909 SetConsolePalette(GraphicsConsoleBuffer,
910 PaletteHandle,
911 SYSPAL_NOSTATIC256);
912
913 /* Set the screen mode flag */
914 ScreenMode = GRAPHICS_MODE;
915
916 return TRUE;
917 }
918
919 static VOID VgaLeaveGraphicsMode(VOID)
920 {
921 /* Release the console framebuffer mutex */
922 ReleaseMutex(ConsoleMutex);
923
924 /* Switch back to the default console text buffer */
925 // VgaSetActiveScreenBuffer(TextConsoleBuffer);
926
927 /* Cleanup the video data */
928 CloseHandle(ConsoleMutex);
929 ConsoleMutex = NULL;
930 ConsoleFramebuffer = NULL;
931 CloseHandle(GraphicsConsoleBuffer);
932 GraphicsConsoleBuffer = NULL;
933
934 DoubleWidth = FALSE;
935 DoubleHeight = FALSE;
936 }
937
938 static BOOL VgaEnterTextMode(PCOORD Resolution)
939 {
940 /* Switch to the text buffer */
941 VgaSetActiveScreenBuffer(TextConsoleBuffer);
942
943 /* Adjust the text framebuffer if we changed the resolution */
944 if (TextResolution.X != Resolution->X ||
945 TextResolution.Y != Resolution->Y)
946 {
947 VgaDetachFromConsole(TRUE);
948
949 /*
950 * VgaAttachToConsoleInternal sets TextResolution to the
951 * new resolution and updates ConsoleInfo.
952 */
953 if (!VgaAttachToConsoleInternal(Resolution))
954 {
955 DisplayMessage(L"An unexpected error occurred!\n");
956 EmulatorTerminate();
957 return FALSE;
958 }
959 }
960 else
961 {
962 VgaUpdateCursorPosition();
963 }
964
965 /* The active framebuffer is now the text framebuffer */
966 ConsoleFramebuffer = TextFramebuffer;
967
968 /*
969 * Set the text mode palette.
970 *
971 * WARNING: This call should fail on Windows (and therefore
972 * we get the default palette and our external behaviour is
973 * just like Windows' one), but it should success on ReactOS
974 * (so that we get console palette changes even for text-mode
975 * screen-buffers, which is a new feature on ReactOS).
976 */
977 SetConsolePalette(TextConsoleBuffer,
978 TextPaletteHandle,
979 SYSPAL_NOSTATIC256);
980
981 /* Set the screen mode flag */
982 ScreenMode = TEXT_MODE;
983
984 return TRUE;
985 }
986
987 static VOID VgaLeaveTextMode(VOID)
988 {
989 /* Reset the active framebuffer */
990 ConsoleFramebuffer = NULL;
991 }
992
993 static VOID VgaChangeMode(VOID)
994 {
995 COORD NewResolution = VgaGetDisplayResolution();
996 SCREEN_MODE NewScreenMode =
997 !(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) ? TEXT_MODE
998 : GRAPHICS_MODE;
999
1000 /*
1001 * No need to switch to a different screen mode + resolution
1002 * if the new ones are the same as the old ones.
1003 */
1004 if ((ScreenMode == NewScreenMode) &&
1005 (CurrResolution.X == NewResolution.X && CurrResolution.Y == NewResolution.Y))
1006 {
1007 goto Quit;
1008 }
1009
1010 if (ScreenMode == GRAPHICS_MODE)
1011 {
1012 /* Leave the current graphics mode */
1013 VgaLeaveGraphicsMode();
1014 }
1015 else
1016 {
1017 /* Leave the current text mode */
1018 VgaLeaveTextMode();
1019 }
1020
1021 /* Update the current resolution */
1022 CurrResolution = NewResolution;
1023
1024 /* The new screen mode will be updated via the VgaEnterText/GraphicsMode functions */
1025
1026 /* Check if the new mode is alphanumeric */
1027 if (NewScreenMode == TEXT_MODE)
1028 {
1029 /* Enter new text mode */
1030 if (!VgaEnterTextMode(&CurrResolution))
1031 {
1032 DisplayMessage(L"An unexpected VGA error occurred while switching into text mode. Error: %u", GetLastError());
1033 EmulatorTerminate();
1034 return;
1035 }
1036 }
1037 else
1038 {
1039 /* Enter graphics mode */
1040 if (!VgaEnterGraphicsMode(&CurrResolution))
1041 {
1042 DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode. Error: %u", GetLastError());
1043 EmulatorTerminate();
1044 return;
1045 }
1046 }
1047
1048 Quit:
1049
1050 /* Trigger a full update of the screen */
1051 NeedsUpdate = TRUE;
1052 UpdateRectangle.Left = 0;
1053 UpdateRectangle.Top = 0;
1054 UpdateRectangle.Right = CurrResolution.X;
1055 UpdateRectangle.Bottom = CurrResolution.Y;
1056
1057 /* Reset the mode change flag */
1058 ModeChanged = FALSE;
1059 }
1060
1061 static VOID VgaUpdateFramebuffer(VOID)
1062 {
1063 SHORT i, j, k;
1064 DWORD AddressSize = VgaGetAddressSize();
1065 DWORD Address = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG],
1066 VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG]);
1067 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1068
1069 /*
1070 * If console framebuffer is NULL, that means something went wrong
1071 * earlier and this is the final display refresh.
1072 */
1073 if (ConsoleFramebuffer == NULL) return;
1074
1075 /* Check if we are in text or graphics mode */
1076 if (ScreenMode == GRAPHICS_MODE)
1077 {
1078 /* Graphics mode */
1079 PBYTE GraphicsBuffer = (PBYTE)ConsoleFramebuffer;
1080 DWORD InterlaceHighBit = VGA_INTERLACE_HIGH_BIT;
1081
1082 /*
1083 * Synchronize access to the graphics framebuffer
1084 * with the console framebuffer mutex.
1085 */
1086 WaitForSingleObject(ConsoleMutex, INFINITE);
1087
1088 /* Shift the high bit right by 1 in odd/even mode */
1089 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1090 {
1091 InterlaceHighBit >>= 1;
1092 }
1093
1094 /* Loop through the scanlines */
1095 for (i = 0; i < CurrResolution.Y; i++)
1096 {
1097 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
1098 {
1099 /* Odd-numbered line in interlaced mode - set the high bit */
1100 Address |= InterlaceHighBit;
1101 }
1102
1103 /* Loop through the pixels */
1104 for (j = 0; j < CurrResolution.X; j++)
1105 {
1106 BYTE PixelData = 0;
1107
1108 /* Check the shifting mode */
1109 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256)
1110 {
1111 /* 4 bits shifted from each plane */
1112
1113 /* Check if this is 16 or 256 color mode */
1114 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1115 {
1116 /* One byte per pixel */
1117 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
1118 + LOWORD((Address + (j / VGA_NUM_BANKS))
1119 * AddressSize)];
1120 }
1121 else
1122 {
1123 /* 4-bits per pixel */
1124
1125 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
1126 + LOWORD((Address + (j / (VGA_NUM_BANKS * 2)))
1127 * AddressSize)];
1128
1129 /* Check if we should use the highest 4 bits or lowest 4 */
1130 if (((j / VGA_NUM_BANKS) % 2) == 0)
1131 {
1132 /* Highest 4 */
1133 PixelData >>= 4;
1134 }
1135 else
1136 {
1137 /* Lowest 4 */
1138 PixelData &= 0x0F;
1139 }
1140 }
1141 }
1142 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG)
1143 {
1144 /* Check if this is 16 or 256 color mode */
1145 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1146 {
1147 // TODO: NOT IMPLEMENTED
1148 DPRINT1("8-bit interleaved mode is not implemented!\n");
1149 }
1150 else
1151 {
1152 /*
1153 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
1154 * then 2 bits shifted from plane 1 and 3 for the next 4
1155 */
1156 DWORD BankNumber = (j / 4) % 2;
1157 DWORD Offset = Address + (j / 8);
1158 BYTE LowPlaneData = VgaMemory[BankNumber * VGA_BANK_SIZE + LOWORD(Offset * AddressSize)];
1159 BYTE HighPlaneData = VgaMemory[(BankNumber + 2) * VGA_BANK_SIZE + LOWORD(Offset * AddressSize)];
1160
1161 /* Extract the two bits from each plane */
1162 LowPlaneData = (LowPlaneData >> (6 - ((j % 4) * 2))) & 0x03;
1163 HighPlaneData = (HighPlaneData >> (6 - ((j % 4) * 2))) & 0x03;
1164
1165 /* Combine them into the pixel */
1166 PixelData = LowPlaneData | (HighPlaneData << 2);
1167 }
1168 }
1169 else
1170 {
1171 /* 1 bit shifted from each plane */
1172
1173 /* Check if this is 16 or 256 color mode */
1174 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
1175 {
1176 /* 8 bits per pixel, 2 on each plane */
1177
1178 for (k = 0; k < VGA_NUM_BANKS; k++)
1179 {
1180 /* The data is on plane k, 4 pixels per byte */
1181 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
1182 + LOWORD((Address + (j / VGA_NUM_BANKS))
1183 * AddressSize)];
1184
1185 /* The mask of the first bit in the pair */
1186 BYTE BitMask = 1 << (((3 - (j % VGA_NUM_BANKS)) * 2) + 1);
1187
1188 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
1189 if (PlaneData & BitMask) PixelData |= 1 << k;
1190
1191 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
1192 if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4);
1193 }
1194 }
1195 else
1196 {
1197 /* 4 bits per pixel, 1 on each plane */
1198
1199 for (k = 0; k < VGA_NUM_BANKS; k++)
1200 {
1201 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
1202 + LOWORD((Address + (j / (VGA_NUM_BANKS * 2)))
1203 * AddressSize)];
1204
1205 /* If the bit on that plane is set, set it */
1206 if (PlaneData & (1 << (7 - (j % 8)))) PixelData |= 1 << k;
1207 }
1208 }
1209 }
1210
1211 if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT))
1212 {
1213 /*
1214 * In 16 color mode, the value is an index to the AC registers
1215 * if external palette access is disabled, otherwise (in case
1216 * of palette loading) it is a blank pixel.
1217 */
1218 PixelData = (VgaAcPalDisable ? VgaAcRegisters[PixelData & 0x0F]
1219 : 0);
1220 }
1221
1222 /* Take into account DoubleVision mode when checking for pixel updates */
1223 if (DoubleWidth && DoubleHeight)
1224 {
1225 /* Now check if the resulting pixel data has changed */
1226 if (GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2)] != PixelData)
1227 {
1228 /* Yes, write the new value */
1229 GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2)] = PixelData;
1230 GraphicsBuffer[(i * 2 * CurrResolution.X * 2) + (j * 2 + 1)] = PixelData;
1231 GraphicsBuffer[((i * 2 + 1) * CurrResolution.X * 2) + (j * 2)] = PixelData;
1232 GraphicsBuffer[((i * 2 + 1) * CurrResolution.X * 2) + (j * 2 + 1)] = PixelData;
1233
1234 /* Mark the specified pixel as changed */
1235 VgaMarkForUpdate(i, j);
1236 }
1237 }
1238 else if (DoubleWidth && !DoubleHeight)
1239 {
1240 /* Now check if the resulting pixel data has changed */
1241 if (GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2)] != PixelData)
1242 {
1243 /* Yes, write the new value */
1244 GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2)] = PixelData;
1245 GraphicsBuffer[(i * CurrResolution.X * 2) + (j * 2 + 1)] = PixelData;
1246
1247 /* Mark the specified pixel as changed */
1248 VgaMarkForUpdate(i, j);
1249 }
1250 }
1251 else if (!DoubleWidth && DoubleHeight)
1252 {
1253 /* Now check if the resulting pixel data has changed */
1254 if (GraphicsBuffer[(i * 2 * CurrResolution.X) + j] != PixelData)
1255 {
1256 /* Yes, write the new value */
1257 GraphicsBuffer[(i * 2 * CurrResolution.X) + j] = PixelData;
1258 GraphicsBuffer[((i * 2 + 1) * CurrResolution.X) + j] = PixelData;
1259
1260 /* Mark the specified pixel as changed */
1261 VgaMarkForUpdate(i, j);
1262 }
1263 }
1264 else // if (!DoubleWidth && !DoubleHeight)
1265 {
1266 /* Now check if the resulting pixel data has changed */
1267 if (GraphicsBuffer[i * CurrResolution.X + j] != PixelData)
1268 {
1269 /* Yes, write the new value */
1270 GraphicsBuffer[i * CurrResolution.X + j] = PixelData;
1271
1272 /* Mark the specified pixel as changed */
1273 VgaMarkForUpdate(i, j);
1274 }
1275 }
1276 }
1277
1278 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) && (i & 1))
1279 {
1280 /* Clear the high bit */
1281 Address &= ~InterlaceHighBit;
1282 }
1283
1284 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_OE) || (i & 1))
1285 {
1286 /* Move to the next scanline */
1287 Address += ScanlineSize;
1288 }
1289 }
1290
1291 /*
1292 * Release the console framebuffer mutex
1293 * so that we allow for repainting.
1294 */
1295 ReleaseMutex(ConsoleMutex);
1296 }
1297 else
1298 {
1299 /* Text mode */
1300 DWORD CurrentAddr;
1301 PCHAR_CELL CharBuffer = (PCHAR_CELL)ConsoleFramebuffer;
1302 CHAR_CELL CharInfo;
1303
1304 /* Loop through the scanlines */
1305 for (i = 0; i < CurrResolution.Y; i++)
1306 {
1307 /* Loop through the characters */
1308 for (j = 0; j < CurrResolution.X; j++)
1309 {
1310 CurrentAddr = LOWORD((Address + j) * AddressSize);
1311
1312 /* Plane 0 holds the character itself */
1313 CharInfo.Char = VgaMemory[CurrentAddr];
1314
1315 /* Plane 1 holds the attribute */
1316 CharInfo.Attributes = VgaMemory[CurrentAddr + VGA_BANK_SIZE];
1317
1318 /* Now check if the resulting character data has changed */
1319 if ((CharBuffer[i * CurrResolution.X + j].Char != CharInfo.Char) ||
1320 (CharBuffer[i * CurrResolution.X + j].Attributes != CharInfo.Attributes))
1321 {
1322 /* Yes, write the new value */
1323 CharBuffer[i * CurrResolution.X + j] = CharInfo;
1324
1325 /* Mark the specified cell as changed */
1326 VgaMarkForUpdate(i, j);
1327 }
1328 }
1329
1330 /* Move to the next scanline */
1331 Address += ScanlineSize;
1332 }
1333 }
1334 }
1335
1336 static VOID VgaUpdateTextCursor(VOID)
1337 {
1338 COORD Position;
1339 CONSOLE_CURSOR_INFO CursorInfo;
1340
1341 BOOL CursorVisible = !(VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x20);
1342 BYTE CursorStart = VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x1F;
1343 BYTE CursorEnd = VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] & 0x1F;
1344
1345 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1346 BYTE TextSize = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1347 WORD Location = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG],
1348 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG]);
1349
1350 /* Just return if we are not in text mode */
1351 if (ScreenMode != TEXT_MODE) return;
1352
1353 if (CursorStart < CursorEnd)
1354 {
1355 /* Visible cursor */
1356 CursorInfo.bVisible = CursorVisible;
1357 CursorInfo.dwSize = (100 * (CursorEnd - CursorStart)) / TextSize;
1358 }
1359 else
1360 {
1361 /* Hidden cursor */
1362 CursorInfo.bVisible = FALSE;
1363 CursorInfo.dwSize = 1; // The size needs to be non-null in order SetConsoleCursorInfo to succeed.
1364 }
1365
1366 /* Add the cursor skew to the location */
1367 Location += (VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] >> 5) & 0x03;
1368
1369 /* Find the coordinates of the new position */
1370 Position.X = (SHORT)(Location % ScanlineSize);
1371 Position.Y = (SHORT)(Location / ScanlineSize);
1372
1373 DPRINT("VgaUpdateTextCursor: X = %d ; Y = %d\n", Position.X, Position.Y);
1374
1375 /* Update the physical cursor */
1376 SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
1377 SetConsoleCursorPosition(TextConsoleBuffer, Position);
1378
1379 /* Reset the cursor changed flag */
1380 CursorChanged = FALSE;
1381 }
1382
1383 static BYTE WINAPI VgaReadPort(USHORT Port)
1384 {
1385 DPRINT("VgaReadPort: Port 0x%X\n", Port);
1386
1387 switch (Port)
1388 {
1389 case VGA_MISC_READ:
1390 return VgaMiscRegister;
1391
1392 case VGA_INSTAT0_READ:
1393 return 0; // Not implemented
1394
1395 case VGA_INSTAT1_READ_MONO:
1396 case VGA_INSTAT1_READ_COLOR:
1397 {
1398 BYTE Result = 0;
1399
1400 /* Reset the AC latch */
1401 VgaAcLatch = FALSE;
1402
1403 /* Set a flag if there is a vertical or horizontal retrace */
1404 if (InVerticalRetrace || InHorizontalRetrace) Result |= VGA_STAT_DD;
1405
1406 /* Set an additional flag if there was a vertical retrace */
1407 if (InVerticalRetrace) Result |= VGA_STAT_VRETRACE;
1408
1409 /* Clear the flags */
1410 InHorizontalRetrace = InVerticalRetrace = FALSE;
1411
1412 return Result;
1413 }
1414
1415 case VGA_FEATURE_READ:
1416 return VgaFeatureRegister;
1417
1418 case VGA_AC_INDEX:
1419 return VgaAcIndex;
1420
1421 case VGA_AC_READ:
1422 return VgaAcRegisters[VgaAcIndex];
1423
1424 case VGA_SEQ_INDEX:
1425 return VgaSeqIndex;
1426
1427 case VGA_SEQ_DATA:
1428 return VgaSeqRegisters[VgaSeqIndex];
1429
1430 case VGA_DAC_MASK:
1431 return VgaDacMask;
1432
1433 case VGA_DAC_READ_INDEX:
1434 /* This returns the read/write state */
1435 return (VgaDacReadWrite ? 0 : 3);
1436
1437 case VGA_DAC_WRITE_INDEX:
1438 return (VgaDacIndex / 3);
1439
1440 case VGA_DAC_DATA:
1441 {
1442 /* Ignore reads in write mode */
1443 if (!VgaDacReadWrite)
1444 {
1445 BYTE Data = VgaDacRegisters[VgaDacIndex++];
1446 VgaDacIndex %= VGA_PALETTE_SIZE;
1447 return Data;
1448 }
1449
1450 break;
1451 }
1452
1453 case VGA_CRTC_INDEX_MONO:
1454 case VGA_CRTC_INDEX_COLOR:
1455 return VgaCrtcIndex;
1456
1457 case VGA_CRTC_DATA_MONO:
1458 case VGA_CRTC_DATA_COLOR:
1459 return VgaCrtcRegisters[VgaCrtcIndex];
1460
1461 case VGA_GC_INDEX:
1462 return VgaGcIndex;
1463
1464 case VGA_GC_DATA:
1465 return VgaGcRegisters[VgaGcIndex];
1466
1467 default:
1468 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port);
1469 break;
1470 }
1471
1472 return 0;
1473 }
1474
1475 static inline VOID VgaWriteSequencer(BYTE Data)
1476 {
1477 ASSERT(VgaSeqIndex < VGA_SEQ_MAX_REG);
1478
1479 /* Save the value */
1480 VgaSeqRegisters[VgaSeqIndex] = Data;
1481 }
1482
1483 static inline VOID VgaWriteGc(BYTE Data)
1484 {
1485 ASSERT(VgaGcIndex < VGA_GC_MAX_REG);
1486
1487 /* Save the value */
1488 VgaGcRegisters[VgaGcIndex] = Data;
1489
1490 /* Check the index */
1491 switch (VgaGcIndex)
1492 {
1493 case VGA_GC_MISC_REG:
1494 {
1495 /* The GC misc register decides if it's text or graphics mode */
1496 ModeChanged = TRUE;
1497 break;
1498 }
1499 }
1500 }
1501
1502 static inline VOID VgaWriteCrtc(BYTE Data)
1503 {
1504 ASSERT(VgaGcIndex < VGA_CRTC_MAX_REG);
1505
1506 /* Save the value */
1507 VgaCrtcRegisters[VgaCrtcIndex] = Data;
1508
1509 /* Check the index */
1510 switch (VgaCrtcIndex)
1511 {
1512 case VGA_CRTC_END_HORZ_DISP_REG:
1513 case VGA_CRTC_VERT_DISP_END_REG:
1514 case VGA_CRTC_OVERFLOW_REG:
1515 case VGA_CRTC_MAX_SCAN_LINE_REG:
1516 {
1517 /* The video mode has changed */
1518 ModeChanged = TRUE;
1519 break;
1520 }
1521
1522 case VGA_CRTC_CURSOR_LOC_LOW_REG:
1523 case VGA_CRTC_CURSOR_LOC_HIGH_REG:
1524 case VGA_CRTC_CURSOR_START_REG:
1525 case VGA_CRTC_CURSOR_END_REG:
1526 {
1527 /* Set the cursor changed flag */
1528 CursorChanged = TRUE;
1529 break;
1530 }
1531 }
1532 }
1533
1534 static inline VOID VgaWriteDac(BYTE Data)
1535 {
1536 INT i, PaletteIndex;
1537 PALETTEENTRY Entry;
1538
1539 /* Set the value */
1540 VgaDacRegisters[VgaDacIndex] = Data;
1541
1542 /* Find the palette index */
1543 PaletteIndex = VgaDacIndex / 3;
1544
1545 /* Fill the entry structure */
1546 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3]);
1547 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 1]);
1548 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 2]);
1549 Entry.peFlags = 0;
1550
1551 /* Update the palette entry */
1552 SetPaletteEntries(PaletteHandle, PaletteIndex, 1, &Entry);
1553
1554 /* Check which text palette entries are affected */
1555 for (i = 0; i <= VGA_AC_PAL_F_REG; i++)
1556 {
1557 if (VgaAcRegisters[i] == PaletteIndex)
1558 {
1559 /* Update the text palette entry */
1560 SetPaletteEntries(TextPaletteHandle, i, 1, &Entry);
1561 }
1562 }
1563
1564 /* Set the palette changed flag */
1565 PaletteChanged = TRUE;
1566
1567 /* Update the index */
1568 VgaDacIndex++;
1569 VgaDacIndex %= VGA_PALETTE_SIZE;
1570 }
1571
1572 static inline VOID VgaWriteAc(BYTE Data)
1573 {
1574 PALETTEENTRY Entry;
1575
1576 ASSERT(VgaAcIndex < VGA_AC_MAX_REG);
1577
1578 /* Save the value */
1579 if (VgaAcIndex <= VGA_AC_PAL_F_REG)
1580 {
1581 if (VgaAcPalDisable) return;
1582
1583 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
1584 if (VgaAcRegisters[VgaAcIndex] != Data)
1585 {
1586 /* Update the AC register */
1587 VgaAcRegisters[VgaAcIndex] = Data;
1588
1589 /* Fill the entry structure */
1590 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3]);
1591 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3 + 1]);
1592 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[Data * 3 + 2]);
1593 Entry.peFlags = 0;
1594
1595 /* Update the palette entry and set the palette change flag */
1596 SetPaletteEntries(TextPaletteHandle, VgaAcIndex, 1, &Entry);
1597 PaletteChanged = TRUE;
1598 }
1599 }
1600 else
1601 {
1602 VgaAcRegisters[VgaAcIndex] = Data;
1603 }
1604 }
1605
1606 static VOID WINAPI VgaWritePort(USHORT Port, BYTE Data)
1607 {
1608 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port, Data);
1609
1610 switch (Port)
1611 {
1612 case VGA_MISC_WRITE:
1613 {
1614 VgaMiscRegister = Data;
1615
1616 if (VgaMiscRegister & 0x01)
1617 {
1618 /* Color emulation */
1619 DPRINT1("Color emulation\n");
1620
1621 /* Register the new I/O Ports */
1622 RegisterIoPort(0x3D4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_COLOR
1623 RegisterIoPort(0x3D5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_COLOR
1624 RegisterIoPort(0x3DA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1625
1626 /* Unregister the old ones */
1627 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1628 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1629 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1630 }
1631 else
1632 {
1633 /* Monochrome emulation */
1634 DPRINT1("Monochrome emulation\n");
1635
1636 /* Register the new I/O Ports */
1637 RegisterIoPort(0x3B4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_MONO
1638 RegisterIoPort(0x3B5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_MONO
1639 RegisterIoPort(0x3BA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1640
1641 /* Unregister the old ones */
1642 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1643 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1644 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1645 }
1646
1647 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1648 break;
1649 }
1650
1651 case VGA_FEATURE_WRITE_MONO:
1652 case VGA_FEATURE_WRITE_COLOR:
1653 {
1654 VgaFeatureRegister = Data;
1655 break;
1656 }
1657
1658 case VGA_AC_INDEX:
1659 // case VGA_AC_WRITE:
1660 {
1661 if (!VgaAcLatch)
1662 {
1663 /* Change the index */
1664 BYTE Index = Data & 0x1F;
1665 if (Index < VGA_AC_MAX_REG) VgaAcIndex = Index;
1666
1667 /*
1668 * Change palette protection by checking for
1669 * the Palette Address Source bit.
1670 */
1671 VgaAcPalDisable = (Data & 0x20) ? TRUE : FALSE;
1672 }
1673 else
1674 {
1675 /* Write the data */
1676 VgaWriteAc(Data);
1677 }
1678
1679 /* Toggle the latch */
1680 VgaAcLatch = !VgaAcLatch;
1681 break;
1682 }
1683
1684 case VGA_SEQ_INDEX:
1685 {
1686 /* Set the sequencer index register */
1687 if (Data < VGA_SEQ_MAX_REG) VgaSeqIndex = Data;
1688 break;
1689 }
1690
1691 case VGA_SEQ_DATA:
1692 {
1693 /* Call the sequencer function */
1694 VgaWriteSequencer(Data);
1695 break;
1696 }
1697
1698 case VGA_DAC_MASK:
1699 {
1700 VgaDacMask = Data;
1701 break;
1702 }
1703
1704 case VGA_DAC_READ_INDEX:
1705 {
1706 VgaDacReadWrite = FALSE;
1707 VgaDacIndex = Data * 3;
1708 break;
1709 }
1710
1711 case VGA_DAC_WRITE_INDEX:
1712 {
1713 VgaDacReadWrite = TRUE;
1714 VgaDacIndex = Data * 3;
1715 break;
1716 }
1717
1718 case VGA_DAC_DATA:
1719 {
1720 /* Ignore writes in read mode */
1721 if (VgaDacReadWrite) VgaWriteDac(Data & 0x3F);
1722 break;
1723 }
1724
1725 case VGA_CRTC_INDEX_MONO:
1726 case VGA_CRTC_INDEX_COLOR:
1727 {
1728 /* Set the CRTC index register */
1729 if (Data < VGA_CRTC_MAX_REG) VgaCrtcIndex = Data;
1730 break;
1731 }
1732
1733 case VGA_CRTC_DATA_MONO:
1734 case VGA_CRTC_DATA_COLOR:
1735 {
1736 /* Call the CRTC function */
1737 VgaWriteCrtc(Data);
1738 break;
1739 }
1740
1741 case VGA_GC_INDEX:
1742 {
1743 /* Set the GC index register */
1744 if (Data < VGA_GC_MAX_REG) VgaGcIndex = Data;
1745 break;
1746 }
1747
1748 case VGA_GC_DATA:
1749 {
1750 /* Call the GC function */
1751 VgaWriteGc(Data);
1752 break;
1753 }
1754
1755 default:
1756 DPRINT1("VgaWritePort: Unknown port 0x%X, Data 0x%02X\n", Port, Data);
1757 break;
1758 }
1759 }
1760
1761 static VOID FASTCALL VgaVerticalRetrace(ULONGLONG ElapsedTime)
1762 {
1763 HANDLE ConsoleBufferHandle = NULL;
1764
1765 UNREFERENCED_PARAMETER(ElapsedTime);
1766
1767 /* Set the vertical retrace flag */
1768 InVerticalRetrace = TRUE;
1769
1770 /* If nothing has changed, just return */
1771 // if (!ModeChanged && !CursorChanged && !PaletteChanged && !NeedsUpdate)
1772 // return;
1773
1774 /* Change the display mode */
1775 if (ModeChanged) VgaChangeMode();
1776
1777 /* Change the text cursor appearance */
1778 if (CursorChanged) VgaUpdateTextCursor();
1779
1780 if (PaletteChanged)
1781 {
1782 /* Trigger a full update of the screen */
1783 NeedsUpdate = TRUE;
1784 UpdateRectangle.Left = 0;
1785 UpdateRectangle.Top = 0;
1786 UpdateRectangle.Right = CurrResolution.X;
1787 UpdateRectangle.Bottom = CurrResolution.Y;
1788
1789 PaletteChanged = FALSE;
1790 }
1791
1792 /* Update the contents of the framebuffer */
1793 VgaUpdateFramebuffer();
1794
1795 /* Ignore if there's nothing to update */
1796 if (!NeedsUpdate) return;
1797
1798 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1799 UpdateRectangle.Left,
1800 UpdateRectangle.Top,
1801 UpdateRectangle.Right,
1802 UpdateRectangle.Bottom);
1803
1804 /* Check if we are in text or graphics mode */
1805 if (ScreenMode == GRAPHICS_MODE)
1806 {
1807 /* Graphics mode */
1808 ConsoleBufferHandle = GraphicsConsoleBuffer;
1809
1810 /* In DoubleVision mode, scale the update rectangle */
1811 if (DoubleWidth)
1812 {
1813 UpdateRectangle.Left *= 2;
1814 UpdateRectangle.Right = UpdateRectangle.Right * 2 + 1;
1815 }
1816 if (DoubleHeight)
1817 {
1818 UpdateRectangle.Top *= 2;
1819 UpdateRectangle.Bottom = UpdateRectangle.Bottom * 2 + 1;
1820 }
1821 }
1822 else
1823 {
1824 /* Text mode */
1825 ConsoleBufferHandle = TextConsoleBuffer;
1826 }
1827
1828 /* Redraw the screen */
1829 __InvalidateConsoleDIBits(ConsoleBufferHandle, &UpdateRectangle);
1830
1831 /* Clear the update flag */
1832 NeedsUpdate = FALSE;
1833 }
1834
1835 static VOID FASTCALL VgaHorizontalRetrace(ULONGLONG ElapsedTime)
1836 {
1837 UNREFERENCED_PARAMETER(ElapsedTime);
1838
1839 /* Set the flag */
1840 InHorizontalRetrace = TRUE;
1841 }
1842
1843 /* PUBLIC FUNCTIONS ***********************************************************/
1844
1845 COORD VgaGetDisplayResolution(VOID)
1846 {
1847 COORD Resolution;
1848 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1849
1850 /* The low 8 bits are in the display registers */
1851 Resolution.X = VgaCrtcRegisters[VGA_CRTC_END_HORZ_DISP_REG];
1852 Resolution.Y = VgaCrtcRegisters[VGA_CRTC_VERT_DISP_END_REG];
1853
1854 /* Set the top bits from the overflow register */
1855 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
1856 {
1857 Resolution.Y |= 1 << 8;
1858 }
1859 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
1860 {
1861 Resolution.Y |= 1 << 9;
1862 }
1863
1864 /* Increase the values by 1 */
1865 Resolution.X++;
1866 Resolution.Y++;
1867
1868 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1869 {
1870 /* Multiply the horizontal resolution by the 9/8 dot mode */
1871 Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
1872 ? 8 : 9;
1873
1874 /* The horizontal resolution is halved in 8-bit mode */
1875 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
1876 }
1877
1878 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
1879 {
1880 /* Halve the vertical resolution */
1881 Resolution.Y >>= 1;
1882 }
1883 else
1884 {
1885 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1886 Resolution.Y /= MaximumScanLine;
1887 }
1888
1889 /* Return the resolution */
1890 return Resolution;
1891 }
1892
1893 BOOLEAN VgaGetDoubleVisionState(PBOOLEAN Horizontal, PBOOLEAN Vertical)
1894 {
1895 if (GraphicsConsoleBuffer == NULL) return FALSE;
1896 if (Horizontal) *Horizontal = DoubleWidth;
1897 if (Vertical) *Vertical = DoubleHeight;
1898 return TRUE;
1899 }
1900
1901 VOID VgaRefreshDisplay(VOID)
1902 {
1903 VgaVerticalRetrace(0);
1904 }
1905
1906 VOID NTAPI VgaReadMemory(ULONG Address, PVOID Buffer, ULONG Size)
1907 {
1908 DWORD i;
1909 DWORD VideoAddress;
1910 PUCHAR BufPtr = (PUCHAR)Buffer;
1911
1912 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
1913 Address = max(min(Address, VgaGetVideoLimitAddress() - 1), VgaGetVideoBaseAddress());
1914 Size = min(Size, VgaGetVideoLimitAddress() - Address + 1);
1915
1916 /* Ignore if video RAM access is disabled */
1917 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1918
1919 /* Loop through each byte */
1920 for (i = 0; i < Size; i++)
1921 {
1922 VideoAddress = VgaTranslateReadAddress(Address + i);
1923
1924 /* Copy the value to the buffer */
1925 BufPtr[i] = VgaMemory[VideoAddress];
1926 }
1927
1928 /* Load the latch registers */
1929 VgaLatchRegisters[0] = VgaMemory[LOWORD(VideoAddress)];
1930 VgaLatchRegisters[1] = VgaMemory[VGA_BANK_SIZE + LOWORD(VideoAddress)];
1931 VgaLatchRegisters[2] = VgaMemory[(2 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1932 VgaLatchRegisters[3] = VgaMemory[(3 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1933 }
1934
1935 BOOLEAN NTAPI VgaWriteMemory(ULONG Address, PVOID Buffer, ULONG Size)
1936 {
1937 DWORD i, j;
1938 DWORD VideoAddress;
1939 PUCHAR BufPtr = (PUCHAR)Buffer;
1940
1941 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
1942 Address = max(min(Address, VgaGetVideoLimitAddress() - 1), VgaGetVideoBaseAddress());
1943 Size = min(Size, VgaGetVideoLimitAddress() - Address + 1);
1944
1945 /* Ignore if video RAM access is disabled */
1946 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return TRUE;
1947
1948 /* Also ignore if write access to all planes is disabled */
1949 if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return TRUE;
1950
1951 /* Loop through each byte */
1952 for (i = 0; i < Size; i++)
1953 {
1954 VideoAddress = VgaTranslateWriteAddress(Address + i);
1955
1956 for (j = 0; j < VGA_NUM_BANKS; j++)
1957 {
1958 /* Make sure the page is writeable */
1959 if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue;
1960
1961 /* Check if this is chain-4 mode */
1962 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
1963 {
1964 if (((Address + i) & 0x03) != j)
1965 {
1966 /* This plane will not be accessed */
1967 continue;
1968 }
1969 }
1970
1971 /* Check if this is odd-even mode */
1972 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1973 {
1974 if (((Address + i) & 0x01) != (j & 1))
1975 {
1976 /* This plane will not be accessed */
1977 continue;
1978 }
1979 }
1980
1981 /* Copy the value to the VGA memory */
1982 VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(BufPtr[i], j);
1983 }
1984 }
1985
1986 return TRUE;
1987 }
1988
1989 VOID VgaClearMemory(VOID)
1990 {
1991 RtlZeroMemory(VgaMemory, sizeof(VgaMemory));
1992 }
1993
1994 VOID VgaWriteFont(UINT FontNumber, CONST UCHAR* FontData, UINT Height)
1995 {
1996 UINT i, j;
1997 PUCHAR FontMemory = (PUCHAR)&VgaMemory[VGA_BANK_SIZE * VGA_FONT_BANK + (FontNumber * VGA_FONT_SIZE)];
1998
1999 ASSERT(Height <= VGA_MAX_FONT_HEIGHT);
2000
2001 for (i = 0 ; i < VGA_FONT_CHARACTERS; i++)
2002 {
2003 /* Write the character */
2004 for (j = 0; j < Height; j++)
2005 {
2006 FontMemory[i * VGA_MAX_FONT_HEIGHT + j] = FontData[i * Height + j];
2007 }
2008
2009 /* Clear the unused part */
2010 for (j = Height; j < VGA_MAX_FONT_HEIGHT; j++)
2011 {
2012 FontMemory[i * VGA_MAX_FONT_HEIGHT + j] = 0;
2013 }
2014 }
2015 }
2016
2017 VOID ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent)
2018 {
2019 DPRINT1("Screen events not handled\n");
2020 }
2021
2022 BOOL VgaAttachToConsole(VOID)
2023 {
2024 //
2025 // FIXME: We should go back to the saved screen state
2026 //
2027 if (TextResolution.X == 0 || TextResolution.Y == 0)
2028 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
2029
2030 if (TextResolution.X == 0) TextResolution.X = 80;
2031 if (TextResolution.Y == 0) TextResolution.Y = 25;
2032
2033 return VgaAttachToConsoleInternal(&TextResolution);
2034 }
2035
2036 VOID VgaDetachFromConsole(BOOL ChangingMode)
2037 {
2038 ULONG dummyLength;
2039 PVOID dummyPtr;
2040 COORD dummySize = {0};
2041
2042 //
2043 // FIXME: We should save the screen state
2044 //
2045
2046 __RegisterConsoleVDM(0,
2047 NULL,
2048 NULL,
2049 NULL,
2050 0,
2051 &dummyLength,
2052 &dummyPtr,
2053 NULL,
2054 0,
2055 dummySize,
2056 &dummyPtr);
2057
2058 TextFramebuffer = NULL;
2059
2060 if (!ChangingMode)
2061 {
2062 SMALL_RECT ConRect;
2063
2064 /* Restore the old screen buffer */
2065 VgaSetActiveScreenBuffer(TextConsoleBuffer);
2066
2067 /* Restore the original console size */
2068 ConRect.Left = 0;
2069 ConRect.Top = 0;
2070 ConRect.Right = ConRect.Left + OrgConsoleBufferInfo.srWindow.Right - OrgConsoleBufferInfo.srWindow.Left;
2071 ConRect.Bottom = ConRect.Top + OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top ;
2072 /*
2073 * See the following trick explanation in VgaAttachToConsoleInternal.
2074 */
2075 SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
2076 SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
2077 SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize);
2078
2079 /* Restore the original cursor shape */
2080 SetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo);
2081 }
2082 }
2083
2084 BOOLEAN VgaInitialize(HANDLE TextHandle)
2085 {
2086 /* Save the default text-mode console output handle */
2087 if (!IsConsoleHandle(TextHandle)) return FALSE;
2088 TextConsoleBuffer = TextHandle;
2089
2090 /* Save the original cursor and console screen buffer information */
2091 if (!GetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo) ||
2092 !GetConsoleScreenBufferInfo(TextConsoleBuffer, &OrgConsoleBufferInfo))
2093 {
2094 return FALSE;
2095 }
2096 ConsoleInfo = OrgConsoleBufferInfo;
2097
2098 /* Initialize the VGA palette and fail if it isn't successfully created */
2099 if (!VgaInitializePalette()) return FALSE;
2100 /***/ VgaResetPalette(); /***/
2101
2102 /* Switch to the text buffer */
2103 VgaSetActiveScreenBuffer(TextConsoleBuffer);
2104
2105 /* Clear the VGA memory */
2106 VgaClearMemory();
2107
2108 /* Register the memory hook */
2109 MemInstallFastMemoryHook((PVOID)0xA0000, 0x20000, VgaReadMemory, VgaWriteMemory);
2110
2111 /* Register the I/O Ports */
2112 RegisterIoPort(0x3CC, VgaReadPort, NULL); // VGA_MISC_READ
2113 RegisterIoPort(0x3C2, VgaReadPort, VgaWritePort); // VGA_MISC_WRITE, VGA_INSTAT0_READ
2114 RegisterIoPort(0x3CA, VgaReadPort, NULL); // VGA_FEATURE_READ
2115 RegisterIoPort(0x3C0, VgaReadPort, VgaWritePort); // VGA_AC_INDEX, VGA_AC_WRITE
2116 RegisterIoPort(0x3C1, VgaReadPort, NULL); // VGA_AC_READ
2117 RegisterIoPort(0x3C4, VgaReadPort, VgaWritePort); // VGA_SEQ_INDEX
2118 RegisterIoPort(0x3C5, VgaReadPort, VgaWritePort); // VGA_SEQ_DATA
2119 RegisterIoPort(0x3C6, VgaReadPort, VgaWritePort); // VGA_DAC_MASK
2120 RegisterIoPort(0x3C7, VgaReadPort, VgaWritePort); // VGA_DAC_READ_INDEX
2121 RegisterIoPort(0x3C8, VgaReadPort, VgaWritePort); // VGA_DAC_WRITE_INDEX
2122 RegisterIoPort(0x3C9, VgaReadPort, VgaWritePort); // VGA_DAC_DATA
2123 RegisterIoPort(0x3CE, VgaReadPort, VgaWritePort); // VGA_GC_INDEX
2124 RegisterIoPort(0x3CF, VgaReadPort, VgaWritePort); // VGA_GC_DATA
2125
2126 /* CGA ports for compatibility, unimplemented */
2127 RegisterIoPort(0x3D8, VgaReadPort, VgaWritePort); // CGA_MODE_CTRL_REG
2128 RegisterIoPort(0x3D9, VgaReadPort, VgaWritePort); // CGA_PAL_CTRL_REG
2129
2130 HSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(31469), VgaHorizontalRetrace);
2131 VSyncTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, HZ_TO_NS(60), VgaVerticalRetrace);
2132
2133 /* Return success */
2134 return TRUE;
2135 }
2136
2137 VOID VgaCleanup(VOID)
2138 {
2139 DestroyHardwareTimer(VSyncTimer);
2140 DestroyHardwareTimer(HSyncTimer);
2141
2142 if (ScreenMode == GRAPHICS_MODE)
2143 {
2144 /* Leave the current graphics mode */
2145 VgaLeaveGraphicsMode();
2146 }
2147 else
2148 {
2149 /* Leave the current text mode */
2150 VgaLeaveTextMode();
2151 }
2152
2153 VgaDetachFromConsole(FALSE);
2154 MemRemoveFastMemoryHook((PVOID)0xA0000, 0x20000);
2155
2156 CloseHandle(AnotherEvent);
2157 CloseHandle(EndEvent);
2158 CloseHandle(StartEvent);
2159 }
2160
2161 /* EOF */