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