cab69a44b10b9e87ef14a469e8b00dcbdfb1e0d6
[reactos.git] / subsystems / ntvdm / 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
16 #include "io.h"
17 #include "bios.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 static BYTE VgaMemory[VGA_NUM_BANKS * VGA_BANK_SIZE];
175 static LPVOID ConsoleFramebuffer = NULL;
176 static HANDLE TextConsoleBuffer = NULL;
177 static HANDLE GraphicsConsoleBuffer = NULL;
178 static HANDLE ConsoleMutex = NULL;
179 static HPALETTE PaletteHandle = NULL;
180 static BOOLEAN DoubleVision = FALSE;
181
182 static BYTE VgaLatchRegisters[VGA_NUM_BANKS] = {0, 0, 0, 0};
183
184 static BYTE VgaMiscRegister;
185 static BYTE VgaFeatureRegister;
186
187 static BYTE VgaSeqIndex = VGA_SEQ_RESET_REG;
188 static BYTE VgaSeqRegisters[VGA_SEQ_MAX_REG];
189
190 static BYTE VgaCrtcIndex = VGA_CRTC_HORZ_TOTAL_REG;
191 static BYTE VgaCrtcRegisters[VGA_CRTC_MAX_REG];
192
193 static BYTE VgaGcIndex = VGA_GC_RESET_REG;
194 static BYTE VgaGcRegisters[VGA_GC_MAX_REG];
195
196 static BOOLEAN VgaAcLatch = FALSE;
197 static BOOLEAN VgaAcPalDisable = TRUE;
198 static BYTE VgaAcIndex = VGA_AC_PAL_0_REG;
199 static BYTE VgaAcRegisters[VGA_AC_MAX_REG];
200
201 // static VGA_REGISTERS VgaRegisters;
202
203 static BYTE VgaDacMask = 0xFF;
204 static WORD VgaDacIndex = 0;
205 static BOOLEAN VgaDacReadWrite = FALSE;
206 static BYTE VgaDacRegisters[VGA_PALETTE_SIZE];
207
208 static BOOLEAN InVerticalRetrace = FALSE;
209 static BOOLEAN InHorizontalRetrace = FALSE;
210
211 static BOOLEAN NeedsUpdate = FALSE;
212 static BOOLEAN ModeChanged = TRUE;
213 static BOOLEAN CursorMoved = FALSE;
214 static BOOLEAN PaletteChanged = FALSE;
215
216 static
217 enum SCREEN_MODE
218 {
219 TEXT_MODE,
220 GRAPHICS_MODE
221 } ScreenMode = TEXT_MODE;
222
223 static SMALL_RECT UpdateRectangle = { 0, 0, 0, 0 };
224
225 /* PRIVATE FUNCTIONS **********************************************************/
226
227 static inline INT VgaGetAddressSize(VOID)
228 {
229 if (VgaCrtcRegisters[VGA_CRTC_UNDERLINE_REG] & VGA_CRTC_UNDERLINE_DWORD)
230 {
231 /* Double-word addressing */
232 return 4; // sizeof(DWORD)
233 }
234
235 if (VgaCrtcRegisters[VGA_CRTC_MODE_CONTROL_REG] & VGA_CRTC_MODE_CONTROL_BYTE)
236 {
237 /* Byte addressing */
238 return 1; // sizeof(BYTE)
239 }
240
241 /* Word addressing */
242 return 2; // sizeof(WORD)
243 }
244
245 static inline DWORD VgaTranslateReadAddress(DWORD Address)
246 {
247 DWORD Offset = Address - VgaGetVideoBaseAddress();
248 BYTE Plane;
249
250 /* Check for chain-4 and odd-even mode */
251 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
252 {
253 /* The lowest two bits are the plane number */
254 Plane = Offset & 3;
255 Offset >>= 2;
256 }
257 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
258 {
259 /* The LSB is the plane number */
260 Plane = Offset & 1;
261 Offset >>= 1;
262 }
263 else
264 {
265 /* Use the read mode */
266 Plane = VgaGcRegisters[VGA_GC_READ_MAP_SEL_REG] & 0x03;
267 }
268
269 /* Multiply the offset by the address size */
270 Offset *= VgaGetAddressSize();
271
272 return Offset + Plane * VGA_BANK_SIZE;
273 }
274
275 static inline DWORD VgaTranslateWriteAddress(DWORD Address)
276 {
277 DWORD Offset = Address - VgaGetVideoBaseAddress();
278
279 /* Check for chain-4 and odd-even mode */
280 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
281 {
282 /* Shift the offset to the right by 2 */
283 Offset >>= 2;
284 }
285 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
286 {
287 /* Shift the offset to the right by 1 */
288 Offset >>= 1;
289 }
290
291 /* Multiply the offset by the address size */
292 Offset *= VgaGetAddressSize();
293
294 /* Return the offset on plane 0 */
295 return Offset;
296 }
297
298 static inline BYTE VgaTranslateByteForWriting(BYTE Data, BYTE Plane)
299 {
300 BYTE WriteMode = VgaGcRegisters[VGA_GC_MODE_REG] & 3;
301 BYTE BitMask = VgaGcRegisters[VGA_GC_BITMASK_REG];
302
303 if (WriteMode == 1)
304 {
305 /* In write mode 1 just return the latch register */
306 return VgaLatchRegisters[Plane];
307 }
308
309 if (WriteMode != 2)
310 {
311 /* Write modes 0 and 3 rotate the data to the right first */
312 BYTE RotateCount = VgaGcRegisters[VGA_GC_ROTATE_REG] & 7;
313 Data = LOBYTE(((DWORD)Data >> RotateCount) | ((DWORD)Data << (8 - RotateCount)));
314 }
315 else
316 {
317 /* Write mode 2 expands the appropriate bit to all 8 bits */
318 Data = (Data & (1 << Plane)) ? 0xFF : 0x00;
319 }
320
321 if (WriteMode == 0)
322 {
323 /*
324 * In write mode 0, the enable set/reset register decides if the
325 * set/reset bit should be expanded to all 8 bits.
326 */
327 if (VgaGcRegisters[VGA_GC_ENABLE_RESET_REG] & (1 << Plane))
328 {
329 /* Copy the bit from the set/reset register to all 8 bits */
330 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
331 }
332 }
333
334 if (WriteMode != 3)
335 {
336 /* Write modes 0 and 2 then perform a logical operation on the data and latch */
337 BYTE LogicalOperation = (VgaGcRegisters[VGA_GC_ROTATE_REG] >> 3) & 3;
338
339 if (LogicalOperation == 1) Data &= VgaLatchRegisters[Plane];
340 else if (LogicalOperation == 2) Data |= VgaLatchRegisters[Plane];
341 else if (LogicalOperation == 3) Data ^= VgaLatchRegisters[Plane];
342 }
343 else
344 {
345 /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */
346 BitMask &= Data;
347
348 /* Then we expand the bit in the set/reset field */
349 Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00;
350 }
351
352 /* Bits cleared in the bitmask are replaced with latch register bits */
353 Data = (Data & BitMask) | (VgaLatchRegisters[Plane] & (~BitMask));
354
355 /* Return the byte */
356 return Data;
357 }
358
359 static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column)
360 {
361 /* Check if this is the first time the rectangle is updated */
362 if (!NeedsUpdate)
363 {
364 UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT;
365 UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT;
366 }
367
368 /* Expand the rectangle to include the point */
369 UpdateRectangle.Left = min(UpdateRectangle.Left, Column);
370 UpdateRectangle.Right = max(UpdateRectangle.Right, Column);
371 UpdateRectangle.Top = min(UpdateRectangle.Top, Row);
372 UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Row);
373
374 /* Set the update request flag */
375 NeedsUpdate = TRUE;
376 }
377
378 static VOID VgaWriteSequencer(BYTE Data)
379 {
380 ASSERT(VgaSeqIndex < VGA_SEQ_MAX_REG);
381
382 /* Save the value */
383 VgaSeqRegisters[VgaSeqIndex] = Data;
384 }
385
386 static VOID VgaWriteGc(BYTE Data)
387 {
388 ASSERT(VgaGcIndex < VGA_GC_MAX_REG);
389
390 /* Save the value */
391 VgaGcRegisters[VgaGcIndex] = Data;
392
393 /* Check the index */
394 switch (VgaGcIndex)
395 {
396 case VGA_GC_MISC_REG:
397 {
398 /* The GC misc register decides if it's text or graphics mode */
399 ModeChanged = TRUE;
400 break;
401 }
402 }
403 }
404
405 static VOID VgaWriteCrtc(BYTE Data)
406 {
407 ASSERT(VgaGcIndex < VGA_CRTC_MAX_REG);
408
409 /* Save the value */
410 VgaCrtcRegisters[VgaCrtcIndex] = Data;
411
412 /* Check the index */
413 switch (VgaCrtcIndex)
414 {
415 case VGA_CRTC_END_HORZ_DISP_REG:
416 case VGA_CRTC_VERT_DISP_END_REG:
417 case VGA_CRTC_OVERFLOW_REG:
418 {
419 /* The video mode has changed */
420 ModeChanged = TRUE;
421 break;
422 }
423
424 case VGA_CRTC_CURSOR_LOC_LOW_REG:
425 case VGA_CRTC_CURSOR_LOC_HIGH_REG:
426 case VGA_CRTC_CURSOR_START_REG:
427 case VGA_CRTC_CURSOR_END_REG:
428 {
429 /* Set the cursor moved flag */
430 CursorMoved = TRUE;
431 break;
432 }
433 }
434 }
435
436 static VOID VgaWriteDac(BYTE Data)
437 {
438 INT PaletteIndex;
439 PALETTEENTRY Entry;
440
441 /* Set the value */
442 VgaDacRegisters[VgaDacIndex] = Data;
443
444 /* Find the palette index */
445 PaletteIndex = VgaDacIndex / 3;
446
447 /* Fill the entry structure */
448 Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3]);
449 Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 1]);
450 Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 2]);
451 Entry.peFlags = 0;
452
453 /* Update the palette entry and set the palette change flag */
454 SetPaletteEntries(PaletteHandle, PaletteIndex, 1, &Entry);
455 PaletteChanged = TRUE;
456
457 /* Update the index */
458 VgaDacIndex++;
459 VgaDacIndex %= VGA_PALETTE_SIZE;
460 }
461
462 static VOID VgaWriteAc(BYTE Data)
463 {
464 ASSERT(VgaAcIndex < VGA_AC_MAX_REG);
465
466 /* Save the value */
467 if (VgaAcIndex <= VGA_AC_PAL_F_REG)
468 {
469 if (VgaAcPalDisable) return;
470
471 // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex);
472 if (VgaAcRegisters[VgaAcIndex] != Data)
473 {
474 /* Update the AC register and set the palette change flag */
475 VgaAcRegisters[VgaAcIndex] = Data;
476 PaletteChanged = TRUE;
477 }
478 }
479 else
480 {
481 VgaAcRegisters[VgaAcIndex] = Data;
482 }
483 }
484
485 static VOID VgaRestoreDefaultPalette(PPALETTEENTRY Entries, USHORT NumOfEntries)
486 {
487 USHORT i;
488
489 /* Copy the colors of the default palette to the DAC and console palette */
490 for (i = 0; i < NumOfEntries; i++)
491 {
492 /* Set the palette entries */
493 Entries[i].peRed = GetRValue(VgaDefaultPalette[i]);
494 Entries[i].peGreen = GetGValue(VgaDefaultPalette[i]);
495 Entries[i].peBlue = GetBValue(VgaDefaultPalette[i]);
496 Entries[i].peFlags = 0;
497
498 /* Set the DAC registers */
499 VgaDacRegisters[i * 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette[i]));
500 VgaDacRegisters[i * 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette[i]));
501 VgaDacRegisters[i * 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette[i]));
502 }
503 }
504
505 static BOOLEAN VgaInitializePalette(VOID)
506 {
507 LPLOGPALETTE Palette;
508
509 /* Allocate storage space for the palette */
510 Palette = (LPLOGPALETTE)HeapAlloc(GetProcessHeap(),
511 HEAP_ZERO_MEMORY,
512 sizeof(LOGPALETTE) +
513 VGA_MAX_COLORS * sizeof(PALETTEENTRY));
514 if (Palette == NULL) return FALSE;
515
516 /* Initialize the palette */
517 Palette->palVersion = 0x0300;
518 Palette->palNumEntries = VGA_MAX_COLORS;
519
520 /* Restore the default palette */
521 VgaRestoreDefaultPalette(Palette->palPalEntry, Palette->palNumEntries);
522
523 /* Create the palette */
524 PaletteHandle = CreatePalette(Palette);
525
526 /* Free the palette */
527 HeapFree(GetProcessHeap(), 0, Palette);
528
529 /* Fail if the palette wasn't successfully created... */
530 if (PaletteHandle == NULL) return FALSE;
531
532 /* ... otherwise return success */
533 return TRUE;
534 }
535
536 static BOOL VgaEnterGraphicsMode(PCOORD Resolution)
537 {
538 DWORD i;
539 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo;
540 BYTE BitmapInfoBuffer[VGA_BITMAP_INFO_SIZE];
541 LPBITMAPINFO BitmapInfo = (LPBITMAPINFO)BitmapInfoBuffer;
542 LPWORD PaletteIndex = (LPWORD)(BitmapInfo->bmiColors);
543
544 LONG Width = Resolution->X;
545 LONG Height = Resolution->Y;
546
547 /* Use DoubleVision mode if the resolution is too small */
548 if (Width < VGA_MINIMUM_WIDTH && Height < VGA_MINIMUM_HEIGHT)
549 {
550 DoubleVision = TRUE;
551 Width *= 2;
552 Height *= 2;
553 }
554
555 /* Fill the bitmap info header */
556 ZeroMemory(&BitmapInfo->bmiHeader, sizeof(BITMAPINFOHEADER));
557 BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
558 BitmapInfo->bmiHeader.biWidth = Width;
559 BitmapInfo->bmiHeader.biHeight = Height;
560 BitmapInfo->bmiHeader.biBitCount = 8;
561 BitmapInfo->bmiHeader.biPlanes = 1;
562 BitmapInfo->bmiHeader.biCompression = BI_RGB;
563 BitmapInfo->bmiHeader.biSizeImage = Width * Height /* * 1 == biBitCount / 8 */;
564
565 /* Fill the palette data */
566 for (i = 0; i < (VGA_PALETTE_SIZE / 3); i++) PaletteIndex[i] = (WORD)i;
567
568 /* Fill the console graphics buffer info */
569 GraphicsBufferInfo.dwBitMapInfoLength = VGA_BITMAP_INFO_SIZE;
570 GraphicsBufferInfo.lpBitMapInfo = BitmapInfo;
571 GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS;
572
573 /* Create the buffer */
574 GraphicsConsoleBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
575 FILE_SHARE_READ | FILE_SHARE_WRITE,
576 NULL,
577 CONSOLE_GRAPHICS_BUFFER,
578 &GraphicsBufferInfo);
579 if (GraphicsConsoleBuffer == INVALID_HANDLE_VALUE) return FALSE;
580
581 /* Save the framebuffer address and mutex */
582 ConsoleFramebuffer = GraphicsBufferInfo.lpBitMap;
583 ConsoleMutex = GraphicsBufferInfo.hMutex;
584
585 /* Clear the framebuffer */
586 ZeroMemory(ConsoleFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
587
588 /* Set the active buffer */
589 SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer);
590
591 /* Set the graphics mode palette */
592 SetConsolePalette(GraphicsConsoleBuffer,
593 PaletteHandle,
594 SYSPAL_NOSTATIC256);
595
596 /* Set the screen mode flag */
597 ScreenMode = GRAPHICS_MODE;
598
599 return TRUE;
600 }
601
602 static VOID VgaLeaveGraphicsMode(VOID)
603 {
604 /* Release the console framebuffer mutex if needed */
605 ReleaseMutex(ConsoleMutex);
606
607 /* Switch back to the text buffer */
608 SetConsoleActiveScreenBuffer(TextConsoleBuffer);
609
610 /* Cleanup the video data */
611 CloseHandle(ConsoleMutex);
612 ConsoleMutex = NULL;
613 CloseHandle(GraphicsConsoleBuffer);
614 GraphicsConsoleBuffer = NULL;
615 DoubleVision = FALSE;
616 }
617
618 static BOOL VgaEnterTextMode(PCOORD Resolution)
619 {
620 /* Resize the console */
621 SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
622
623 /* Allocate a framebuffer */
624 ConsoleFramebuffer = HeapAlloc(GetProcessHeap(),
625 HEAP_ZERO_MEMORY,
626 Resolution->X * Resolution->Y
627 * sizeof(CHAR_INFO));
628 if (ConsoleFramebuffer == NULL)
629 {
630 DisplayMessage(L"An unexpected error occurred!\n");
631 VdmRunning = FALSE;
632 return FALSE;
633 }
634
635 /*
636 * Set the text mode palette.
637 *
638 * WARNING: This call should fail on Windows (and therefore
639 * we get the default palette and our external behaviour is
640 * just like Windows' one), but it should success on ReactOS
641 * (so that we get console palette changes even for text-mode
642 * screen-buffers, which is a new feature on ReactOS).
643 */
644 SetConsolePalette(TextConsoleBuffer,
645 PaletteHandle,
646 SYSPAL_NOSTATIC256);
647
648 /* Set the screen mode flag */
649 ScreenMode = TEXT_MODE;
650
651 return TRUE;
652 }
653
654 static VOID VgaLeaveTextMode(VOID)
655 {
656 /* Free the old framebuffer */
657 HeapFree(GetProcessHeap(), 0, ConsoleFramebuffer);
658 ConsoleFramebuffer = NULL;
659 }
660
661 static VOID VgaChangeMode(VOID)
662 {
663 COORD Resolution = VgaGetDisplayResolution();
664
665 /* Reset the mode change flag */
666 // ModeChanged = FALSE;
667
668 if (ScreenMode == GRAPHICS_MODE)
669 {
670 /* Leave the current graphics mode */
671 VgaLeaveGraphicsMode();
672 }
673 else
674 {
675 /* Leave the current text mode */
676 VgaLeaveTextMode();
677 }
678
679 /* Check if the new mode is alphanumeric */
680 if (!(VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA))
681 {
682 /* Enter new text mode */
683 if (!VgaEnterTextMode(&Resolution))
684 {
685 DisplayMessage(L"An unexpected VGA error occurred while switching into text mode.");
686 VdmRunning = FALSE;
687 return;
688 }
689 }
690 else
691 {
692 /* Enter 8-bit graphics mode */
693 if (!VgaEnterGraphicsMode(&Resolution))
694 {
695 DisplayMessage(L"An unexpected VGA error occurred while switching into graphics mode.");
696 VdmRunning = FALSE;
697 return;
698 }
699 }
700
701 /* Trigger a full update of the screen */
702 NeedsUpdate = TRUE;
703 UpdateRectangle.Left = 0;
704 UpdateRectangle.Top = 0;
705 UpdateRectangle.Right = Resolution.X;
706 UpdateRectangle.Bottom = Resolution.Y;
707
708 /* Reset the mode change flag */
709 ModeChanged = FALSE;
710 }
711
712 static VOID VgaUpdateFramebuffer(VOID)
713 {
714 INT i, j, k;
715 COORD Resolution = VgaGetDisplayResolution();
716 INT AddressSize = VgaGetAddressSize();
717 DWORD Address = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_START_ADDR_LOW_REG],
718 VgaCrtcRegisters[VGA_CRTC_START_ADDR_HIGH_REG]);
719 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
720
721 /*
722 * If console framebuffer is NULL, that means something went wrong
723 * earlier and this is the final display refresh.
724 */
725 if (ConsoleFramebuffer == NULL) return;
726
727 /* Check if this is text mode or graphics mode */
728 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
729 {
730 /* Graphics mode */
731 PBYTE GraphicsBuffer = (PBYTE)ConsoleFramebuffer;
732
733 /*
734 * Synchronize access to the graphics framebuffer
735 * with the console framebuffer mutex.
736 */
737 WaitForSingleObject(ConsoleMutex, INFINITE);
738
739 /* Loop through the scanlines */
740 for (i = 0; i < Resolution.Y; i++)
741 {
742 /* Loop through the pixels */
743 for (j = 0; j < Resolution.X; j++)
744 {
745 BYTE PixelData = 0;
746
747 /* Check the shifting mode */
748 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFT256)
749 {
750 /* 4 bits shifted from each plane */
751
752 /* Check if this is 16 or 256 color mode */
753 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
754 {
755 /* One byte per pixel */
756 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
757 + (Address + (j / VGA_NUM_BANKS))
758 * AddressSize];
759 }
760 else
761 {
762 /* 4-bits per pixel */
763
764 PixelData = VgaMemory[(j % VGA_NUM_BANKS) * VGA_BANK_SIZE
765 + (Address + (j / (VGA_NUM_BANKS * 2)))
766 * AddressSize];
767
768 /* Check if we should use the highest 4 bits or lowest 4 */
769 if (((j / VGA_NUM_BANKS) % 2) == 0)
770 {
771 /* Highest 4 */
772 PixelData >>= 4;
773 }
774 else
775 {
776 /* Lowest 4 */
777 PixelData &= 0x0F;
778 }
779 }
780 }
781 else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_SHIFTREG)
782 {
783 /* Check if this is 16 or 256 color mode */
784 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
785 {
786 // TODO: NOT IMPLEMENTED
787 DPRINT1("8-bit interleaved mode is not implemented!\n");
788 }
789 else
790 {
791 /*
792 * 2 bits shifted from plane 0 and 2 for the first 4 pixels,
793 * then 2 bits shifted from plane 1 and 3 for the next 4
794 */
795 BYTE LowPlaneData = VgaMemory[((j / 4) % 2) * VGA_BANK_SIZE
796 + (Address + (j / 4)) * AddressSize];
797 BYTE HighPlaneData = VgaMemory[(((j / 4) % 2) + 2) * VGA_BANK_SIZE
798 + (Address + (j / 4)) * AddressSize];
799
800 /* Extract the two bits from each plane */
801 LowPlaneData = (LowPlaneData >> (6 - ((j % 4) * 2))) & 3;
802 HighPlaneData = (HighPlaneData >> (6 - ((j % 4) * 2))) & 3;
803
804 /* Combine them into the pixel */
805 PixelData = LowPlaneData | (HighPlaneData << 2);
806 }
807 }
808 else
809 {
810 /* 1 bit shifted from each plane */
811
812 /* Check if this is 16 or 256 color mode */
813 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT)
814 {
815 /* 8 bits per pixel, 2 on each plane */
816
817 for (k = 0; k < VGA_NUM_BANKS; k++)
818 {
819 /* The data is on plane k, 4 pixels per byte */
820 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
821 + (Address + (j / 4)) * AddressSize];
822
823 /* The mask of the first bit in the pair */
824 BYTE BitMask = 1 << (((3 - (j % 4)) * 2) + 1);
825
826 /* Bits 0, 1, 2 and 3 come from the first bit of the pair */
827 if (PlaneData & BitMask) PixelData |= 1 << k;
828
829 /* Bits 4, 5, 6 and 7 come from the second bit of the pair */
830 if (PlaneData & (BitMask >> 1)) PixelData |= 1 << (k + 4);
831 }
832 }
833 else
834 {
835 /* 4 bits per pixel, 1 on each plane */
836
837 for (k = 0; k < VGA_NUM_BANKS; k++)
838 {
839 BYTE PlaneData = VgaMemory[k * VGA_BANK_SIZE
840 + (Address + (j / 8)) * AddressSize];
841
842 /* If the bit on that plane is set, set it */
843 if (PlaneData & (1 << (7 - (j % 8)))) PixelData |= 1 << k;
844 }
845 }
846 }
847
848 if (!(VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT))
849 {
850 /*
851 * In 16 color mode, the value is an index to the AC registers
852 * if external palette access is disabled, otherwise (in case
853 * of palette loading) it is a blank pixel.
854 */
855 PixelData = (VgaAcPalDisable ? VgaAcRegisters[PixelData & 0x0F]
856 : 0);
857 }
858
859 /* Take into account DoubleVision mode when checking for pixel updates */
860 if (DoubleVision)
861 {
862 /* Now check if the resulting pixel data has changed */
863 if (GraphicsBuffer[(i * Resolution.X * 4) + (j * 2)] != PixelData)
864 {
865 /* Yes, write the new value */
866 GraphicsBuffer[(i * Resolution.X * 4) + (j * 2)] = PixelData;
867 GraphicsBuffer[(i * Resolution.X * 4) + (j * 2 + 1)] = PixelData;
868 GraphicsBuffer[((i * 2 + 1) * Resolution.X * 2) + (j * 2)] = PixelData;
869 GraphicsBuffer[((i * 2 + 1) * Resolution.X * 2) + (j * 2 + 1)] = PixelData;
870
871 /* Mark the specified pixel as changed */
872 VgaMarkForUpdate(i, j);
873 }
874 }
875 else
876 {
877 /* Now check if the resulting pixel data has changed */
878 if (GraphicsBuffer[i * Resolution.X + j] != PixelData)
879 {
880 /* Yes, write the new value */
881 GraphicsBuffer[i * Resolution.X + j] = PixelData;
882
883 /* Mark the specified pixel as changed */
884 VgaMarkForUpdate(i, j);
885 }
886 }
887 }
888
889 /* Move to the next scanline */
890 Address += ScanlineSize;
891 }
892
893 /*
894 * Release the console framebuffer mutex
895 * so that we allow for repainting.
896 */
897 ReleaseMutex(ConsoleMutex);
898 }
899 else
900 {
901 /* Text mode */
902 PCHAR_INFO CharBuffer = (PCHAR_INFO)ConsoleFramebuffer;
903
904 /* Loop through the scanlines */
905 for (i = 0; i < Resolution.Y; i++)
906 {
907 /* Loop through the characters */
908 for (j = 0; j < Resolution.X; j++)
909 {
910 DWORD CurrentAddr = LOWORD((Address + j) * AddressSize);
911 CHAR_INFO CharInfo;
912
913 /* Plane 0 holds the character itself */
914 CharInfo.Char.AsciiChar = VgaMemory[CurrentAddr];
915
916 /* Plane 1 holds the attribute */
917 CharInfo.Attributes = VgaMemory[CurrentAddr + VGA_BANK_SIZE];
918
919 /* Now check if the resulting character data has changed */
920 if ((CharBuffer[i * Resolution.X + j].Char.AsciiChar != CharInfo.Char.AsciiChar)
921 || (CharBuffer[i * Resolution.X + j].Attributes != CharInfo.Attributes))
922 {
923 /* Yes, write the new value */
924 CharBuffer[i * Resolution.X + j] = CharInfo;
925
926 /* Mark the specified cell as changed */
927 VgaMarkForUpdate(i, j);
928 }
929 }
930
931 /* Move to the next scanline */
932 Address += ScanlineSize;
933 }
934 }
935 }
936
937 static VOID VgaUpdateTextCursor(VOID)
938 {
939 COORD Position;
940 CONSOLE_CURSOR_INFO CursorInfo;
941 BYTE CursorStart = VgaCrtcRegisters[VGA_CRTC_CURSOR_START_REG] & 0x3F;
942 BYTE CursorEnd = VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] & 0x1F;
943 DWORD ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
944 BYTE TextSize = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
945 WORD Location = MAKEWORD(VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG],
946 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG]);
947
948 /* Just return if we are not in text mode */
949 if ((VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA) != 0) return;
950
951 if (CursorStart < CursorEnd)
952 {
953 /* Visible cursor */
954 CursorInfo.bVisible = TRUE;
955 CursorInfo.dwSize = (100 * (CursorEnd - CursorStart)) / TextSize;
956 }
957 else
958 {
959 /* No cursor */
960 CursorInfo.bVisible = FALSE;
961 CursorInfo.dwSize = 0;
962 }
963
964 /* Add the cursor skew to the location */
965 Location += (VgaCrtcRegisters[VGA_CRTC_CURSOR_END_REG] >> 5) & 3;
966
967 /* Find the coordinates of the new position */
968 Position.X = (WORD)(Location % ScanlineSize);
969 Position.Y = (WORD)(Location / ScanlineSize);
970
971 /* Update the physical cursor */
972 SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
973 SetConsoleCursorPosition(TextConsoleBuffer, Position);
974
975 /* Reset the cursor move flag */
976 CursorMoved = FALSE;
977 }
978
979 /* PUBLIC FUNCTIONS ***********************************************************/
980
981 DWORD VgaGetVideoBaseAddress(VOID)
982 {
983 return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
984 }
985
986 DWORD VgaGetVideoLimitAddress(VOID)
987 {
988 return MemoryLimit[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
989 }
990
991 COORD VgaGetDisplayResolution(VOID)
992 {
993 COORD Resolution;
994 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
995
996 /* The low 8 bits are in the display registers */
997 Resolution.X = VgaCrtcRegisters[VGA_CRTC_END_HORZ_DISP_REG];
998 Resolution.Y = VgaCrtcRegisters[VGA_CRTC_VERT_DISP_END_REG];
999
1000 /* Set the top bits from the overflow register */
1001 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
1002 {
1003 Resolution.Y |= 1 << 8;
1004 }
1005 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
1006 {
1007 Resolution.Y |= 1 << 9;
1008 }
1009
1010 /* Increase the values by 1 */
1011 Resolution.X++;
1012 Resolution.Y++;
1013
1014 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1015 {
1016 /* Multiply the horizontal resolution by the 9/8 dot mode */
1017 Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
1018 ? 8 : 9;
1019
1020 /* The horizontal resolution is halved in 8-bit mode */
1021 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
1022 }
1023
1024 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
1025 {
1026 /* Halve the vertical resolution */
1027 Resolution.Y >>= 1;
1028 }
1029
1030 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1031 Resolution.Y /= MaximumScanLine;
1032
1033 /* Return the resolution */
1034 return Resolution;
1035 }
1036
1037 VOID VgaRefreshDisplay(VOID)
1038 {
1039 HANDLE ConsoleBufferHandle = NULL;
1040 COORD Resolution;
1041
1042 /* Set the vertical retrace flag */
1043 InVerticalRetrace = TRUE;
1044
1045 /* If nothing has changed, just return */
1046 if (!ModeChanged && !CursorMoved && !PaletteChanged && !NeedsUpdate)
1047 return;
1048
1049 /* Retrieve the current resolution */
1050 Resolution = VgaGetDisplayResolution();
1051
1052 /* Change the display mode */
1053 if (ModeChanged) VgaChangeMode();
1054
1055 /* Change the text cursor location */
1056 if (CursorMoved) VgaUpdateTextCursor();
1057
1058 if (PaletteChanged)
1059 {
1060 /* Trigger a full update of the screen */
1061 NeedsUpdate = TRUE;
1062 UpdateRectangle.Left = 0;
1063 UpdateRectangle.Top = 0;
1064 UpdateRectangle.Right = Resolution.X;
1065 UpdateRectangle.Bottom = Resolution.Y;
1066
1067 PaletteChanged = FALSE;
1068 }
1069
1070 /* Update the contents of the framebuffer */
1071 VgaUpdateFramebuffer();
1072
1073 /* Ignore if there's nothing to update */
1074 if (!NeedsUpdate) return;
1075
1076 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1077 UpdateRectangle.Left,
1078 UpdateRectangle.Top,
1079 UpdateRectangle.Right,
1080 UpdateRectangle.Bottom);
1081
1082 /* Check if this is text mode or graphics mode */
1083 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1084 {
1085 /* Graphics mode */
1086 ConsoleBufferHandle = GraphicsConsoleBuffer;
1087 }
1088 else
1089 {
1090 /* Text mode */
1091 COORD Origin = { UpdateRectangle.Left, UpdateRectangle.Top };
1092 ConsoleBufferHandle = TextConsoleBuffer;
1093
1094 /* Write the data to the console */
1095 WriteConsoleOutputA(TextConsoleBuffer,
1096 (PCHAR_INFO)ConsoleFramebuffer,
1097 Resolution,
1098 Origin,
1099 &UpdateRectangle);
1100 }
1101
1102 /* In DoubleVision mode, scale the update rectangle */
1103 if (DoubleVision)
1104 {
1105 UpdateRectangle.Left *= 2;
1106 UpdateRectangle.Top *= 2;
1107 UpdateRectangle.Right = UpdateRectangle.Right * 2 + 1;
1108 UpdateRectangle.Bottom = UpdateRectangle.Bottom * 2 + 1;
1109 }
1110
1111 /* Redraw the screen */
1112 InvalidateConsoleDIBits(ConsoleBufferHandle, &UpdateRectangle);
1113
1114 /* Clear the update flag */
1115 NeedsUpdate = FALSE;
1116 }
1117
1118 VOID VgaHorizontalRetrace(VOID)
1119 {
1120 /* Set the flag */
1121 InHorizontalRetrace = TRUE;
1122 }
1123
1124 VOID VgaReadMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
1125 {
1126 DWORD i;
1127 DWORD VideoAddress;
1128
1129 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
1130
1131 /* Ignore if video RAM access is disabled */
1132 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1133
1134 /* Loop through each byte */
1135 for (i = 0; i < Size; i++)
1136 {
1137 VideoAddress = VgaTranslateReadAddress(Address + i);
1138
1139 /* Load the latch registers */
1140 VgaLatchRegisters[0] = VgaMemory[LOWORD(VideoAddress)];
1141 VgaLatchRegisters[1] = VgaMemory[VGA_BANK_SIZE + LOWORD(VideoAddress)];
1142 VgaLatchRegisters[2] = VgaMemory[(2 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1143 VgaLatchRegisters[3] = VgaMemory[(3 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1144
1145 /* Copy the value to the buffer */
1146 Buffer[i] = VgaMemory[VideoAddress];
1147 }
1148 }
1149
1150 VOID VgaWriteMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
1151 {
1152 DWORD i, j;
1153 DWORD VideoAddress;
1154
1155 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
1156
1157 /* Ignore if video RAM access is disabled */
1158 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1159
1160 /* Also ignore if write access to all planes is disabled */
1161 if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return;
1162
1163 /* Loop through each byte */
1164 for (i = 0; i < Size; i++)
1165 {
1166 VideoAddress = VgaTranslateWriteAddress(Address + i);
1167
1168 for (j = 0; j < VGA_NUM_BANKS; j++)
1169 {
1170 /* Make sure the page is writeable */
1171 if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue;
1172
1173 /* Check if this is chain-4 mode */
1174 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
1175 {
1176 if (((Address + i) & 3) != j)
1177 {
1178 /* This plane will not be accessed */
1179 continue;
1180 }
1181 }
1182
1183 /* Check if this is odd-even mode */
1184 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1185 {
1186 if (((Address + i) & 1) != (j & 1))
1187 {
1188 /* This plane will not be accessed */
1189 continue;
1190 }
1191 }
1192
1193 /* Copy the value to the VGA memory */
1194 VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(Buffer[i], j);
1195 }
1196 }
1197 }
1198
1199 BYTE WINAPI VgaReadPort(ULONG Port)
1200 {
1201 DPRINT("VgaReadPort: Port 0x%X\n", Port);
1202
1203 switch (Port)
1204 {
1205 case VGA_MISC_READ:
1206 return VgaMiscRegister;
1207
1208 case VGA_INSTAT0_READ:
1209 return 0; // Not implemented
1210
1211 case VGA_INSTAT1_READ_MONO:
1212 case VGA_INSTAT1_READ_COLOR:
1213 {
1214 BYTE Result = 0;
1215
1216 /* Reset the AC latch */
1217 VgaAcLatch = FALSE;
1218
1219 /* Set a flag if there is a vertical or horizontal retrace */
1220 if (InVerticalRetrace || InHorizontalRetrace) Result |= VGA_STAT_DD;
1221
1222 /* Set an additional flag if there was a vertical retrace */
1223 if (InVerticalRetrace) Result |= VGA_STAT_VRETRACE;
1224
1225 /* Clear the flags */
1226 InHorizontalRetrace = InVerticalRetrace = FALSE;
1227
1228 return Result;
1229 }
1230
1231 case VGA_FEATURE_READ:
1232 return VgaFeatureRegister;
1233
1234 case VGA_AC_INDEX:
1235 return VgaAcIndex;
1236
1237 case VGA_AC_READ:
1238 return VgaAcRegisters[VgaAcIndex];
1239
1240 case VGA_SEQ_INDEX:
1241 return VgaSeqIndex;
1242
1243 case VGA_SEQ_DATA:
1244 return VgaSeqRegisters[VgaSeqIndex];
1245
1246 case VGA_DAC_MASK:
1247 return VgaDacMask;
1248
1249 case VGA_DAC_READ_INDEX:
1250 /* This returns the read/write state */
1251 return (VgaDacReadWrite ? 0 : 3);
1252
1253 case VGA_DAC_WRITE_INDEX:
1254 return (VgaDacIndex / 3);
1255
1256 case VGA_DAC_DATA:
1257 {
1258 /* Ignore reads in write mode */
1259 if (!VgaDacReadWrite)
1260 {
1261 BYTE Data = VgaDacRegisters[VgaDacIndex++];
1262 VgaDacIndex %= VGA_PALETTE_SIZE;
1263 return Data;
1264 }
1265
1266 break;
1267 }
1268
1269 case VGA_CRTC_INDEX_MONO:
1270 case VGA_CRTC_INDEX_COLOR:
1271 return VgaCrtcIndex;
1272
1273 case VGA_CRTC_DATA_MONO:
1274 case VGA_CRTC_DATA_COLOR:
1275 return VgaCrtcRegisters[VgaCrtcIndex];
1276
1277 case VGA_GC_INDEX:
1278 return VgaGcIndex;
1279
1280 case VGA_GC_DATA:
1281 return VgaGcRegisters[VgaGcIndex];
1282
1283 default:
1284 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port);
1285 break;
1286 }
1287
1288 return 0;
1289 }
1290
1291 VOID WINAPI VgaWritePort(ULONG Port, BYTE Data)
1292 {
1293 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port, Data);
1294
1295 switch (Port)
1296 {
1297 case VGA_MISC_WRITE:
1298 {
1299 VgaMiscRegister = Data;
1300
1301 if (VgaMiscRegister & 0x01)
1302 {
1303 /* Color emulation */
1304 DPRINT1("Color emulation\n");
1305
1306 /* Register the new I/O Ports */
1307 RegisterIoPort(0x3D4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_COLOR
1308 RegisterIoPort(0x3D5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_COLOR
1309 RegisterIoPort(0x3DA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1310
1311 /* Unregister the old ones */
1312 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1313 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1314 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1315 }
1316 else
1317 {
1318 /* Monochrome emulation */
1319 DPRINT1("Monochrome emulation\n");
1320
1321 /* Register the new I/O Ports */
1322 RegisterIoPort(0x3B4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_MONO
1323 RegisterIoPort(0x3B5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_MONO
1324 RegisterIoPort(0x3BA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1325
1326 /* Unregister the old ones */
1327 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1328 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1329 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1330 }
1331
1332 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1333 break;
1334 }
1335
1336 case VGA_FEATURE_WRITE_MONO:
1337 case VGA_FEATURE_WRITE_COLOR:
1338 {
1339 VgaFeatureRegister = Data;
1340 break;
1341 }
1342
1343 case VGA_AC_INDEX:
1344 // case VGA_AC_WRITE:
1345 {
1346 if (!VgaAcLatch)
1347 {
1348 /* Change the index */
1349 BYTE Index = Data & 0x1F;
1350 if (Index < VGA_AC_MAX_REG) VgaAcIndex = Index;
1351
1352 /*
1353 * Change palette protection by checking for
1354 * the Palette Address Source bit.
1355 */
1356 VgaAcPalDisable = (Data & 0x20) ? TRUE : FALSE;
1357 }
1358 else
1359 {
1360 /* Write the data */
1361 VgaWriteAc(Data);
1362 }
1363
1364 /* Toggle the latch */
1365 VgaAcLatch = !VgaAcLatch;
1366 break;
1367 }
1368
1369 case VGA_SEQ_INDEX:
1370 {
1371 /* Set the sequencer index register */
1372 if (Data < VGA_SEQ_MAX_REG) VgaSeqIndex = Data;
1373 break;
1374 }
1375
1376 case VGA_SEQ_DATA:
1377 {
1378 /* Call the sequencer function */
1379 VgaWriteSequencer(Data);
1380 break;
1381 }
1382
1383 case VGA_DAC_MASK:
1384 {
1385 VgaDacMask = Data;
1386 break;
1387 }
1388
1389 case VGA_DAC_READ_INDEX:
1390 {
1391 VgaDacReadWrite = FALSE;
1392 VgaDacIndex = Data * 3;
1393 break;
1394 }
1395
1396 case VGA_DAC_WRITE_INDEX:
1397 {
1398 VgaDacReadWrite = TRUE;
1399 VgaDacIndex = Data * 3;
1400 break;
1401 }
1402
1403 case VGA_DAC_DATA:
1404 {
1405 /* Ignore writes in read mode */
1406 if (VgaDacReadWrite) VgaWriteDac(Data & 0x3F);
1407 break;
1408 }
1409
1410 case VGA_CRTC_INDEX_MONO:
1411 case VGA_CRTC_INDEX_COLOR:
1412 {
1413 /* Set the CRTC index register */
1414 if (Data < VGA_CRTC_MAX_REG) VgaCrtcIndex = Data;
1415 break;
1416 }
1417
1418 case VGA_CRTC_DATA_MONO:
1419 case VGA_CRTC_DATA_COLOR:
1420 {
1421 /* Call the CRTC function */
1422 VgaWriteCrtc(Data);
1423 break;
1424 }
1425
1426 case VGA_GC_INDEX:
1427 {
1428 /* Set the GC index register */
1429 if (Data < VGA_GC_MAX_REG) VgaGcIndex = Data;
1430 break;
1431 }
1432
1433 case VGA_GC_DATA:
1434 {
1435 /* Call the GC function */
1436 VgaWriteGc(Data);
1437 break;
1438 }
1439
1440 default:
1441 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port);
1442 break;
1443 }
1444 }
1445
1446 VOID VgaClearMemory(VOID)
1447 {
1448 ZeroMemory(VgaMemory, sizeof(VgaMemory));
1449 }
1450
1451 VOID VgaResetPalette(VOID)
1452 {
1453 PALETTEENTRY Entries[VGA_MAX_COLORS];
1454
1455 /* Restore the default palette */
1456 VgaRestoreDefaultPalette(Entries, VGA_MAX_COLORS);
1457 SetPaletteEntries(PaletteHandle, 0, VGA_MAX_COLORS, Entries);
1458 PaletteChanged = TRUE;
1459 }
1460
1461 BOOLEAN VgaInitialize(HANDLE TextHandle)
1462 {
1463 INT i, j;
1464 COORD Resolution;
1465 INT AddressSize;
1466 DWORD ScanlineSize;
1467 COORD Origin = { 0, 0 };
1468 SMALL_RECT ScreenRect;
1469 PCHAR_INFO CharBuffer;
1470 DWORD Address = 0;
1471 DWORD CurrentAddr;
1472
1473 /* Initialize the VGA palette and fail if it isn't successfully created */
1474 if (!VgaInitializePalette()) return FALSE;
1475 /***/ VgaResetPalette(); /***/
1476
1477 /* Set the global handle */
1478 TextConsoleBuffer = TextHandle;
1479
1480 /* Register the I/O Ports */
1481 RegisterIoPort(0x3CC, VgaReadPort, NULL); // VGA_MISC_READ
1482 RegisterIoPort(0x3C2, VgaReadPort, VgaWritePort); // VGA_MISC_WRITE, VGA_INSTAT0_READ
1483 RegisterIoPort(0x3CA, VgaReadPort, NULL); // VGA_FEATURE_READ
1484 RegisterIoPort(0x3C0, VgaReadPort, VgaWritePort); // VGA_AC_INDEX, VGA_AC_WRITE
1485 RegisterIoPort(0x3C1, VgaReadPort, NULL); // VGA_AC_READ
1486 RegisterIoPort(0x3C4, VgaReadPort, VgaWritePort); // VGA_SEQ_INDEX
1487 RegisterIoPort(0x3C5, VgaReadPort, VgaWritePort); // VGA_SEQ_DATA
1488 RegisterIoPort(0x3C6, VgaReadPort, VgaWritePort); // VGA_DAC_MASK
1489 RegisterIoPort(0x3C7, VgaReadPort, VgaWritePort); // VGA_DAC_READ_INDEX
1490 RegisterIoPort(0x3C8, VgaReadPort, VgaWritePort); // VGA_DAC_WRITE_INDEX
1491 RegisterIoPort(0x3C9, VgaReadPort, VgaWritePort); // VGA_DAC_DATA
1492 RegisterIoPort(0x3CE, VgaReadPort, VgaWritePort); // VGA_GC_INDEX
1493 RegisterIoPort(0x3CF, VgaReadPort, VgaWritePort); // VGA_GC_DATA
1494
1495 /* Clear the VGA memory */
1496 VgaClearMemory();
1497
1498 /* Set the default video mode */
1499 BiosSetVideoMode(BIOS_DEFAULT_VIDEO_MODE);
1500 VgaChangeMode();
1501
1502 /* Get the data */
1503 Resolution = VgaGetDisplayResolution();
1504 CharBuffer = (PCHAR_INFO)ConsoleFramebuffer;
1505 AddressSize = VgaGetAddressSize();
1506 ScreenRect.Left = ScreenRect.Top = 0;
1507 ScreenRect.Right = Resolution.X;
1508 ScreenRect.Bottom = Resolution.Y;
1509 ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
1510
1511 /* Read the data from the console into the framebuffer */
1512 ReadConsoleOutputA(TextConsoleBuffer,
1513 CharBuffer,
1514 Resolution,
1515 Origin,
1516 &ScreenRect);
1517
1518 /* Loop through the scanlines */
1519 for (i = 0; i < Resolution.Y; i++)
1520 {
1521 /* Loop through the characters */
1522 for (j = 0; j < Resolution.X; j++)
1523 {
1524 CurrentAddr = LOWORD((Address + j) * AddressSize);
1525
1526 /* Store the character in plane 0 */
1527 VgaMemory[CurrentAddr] = CharBuffer[i * Resolution.X + j].Char.AsciiChar;
1528
1529 /* Store the attribute in plane 1 */
1530 VgaMemory[CurrentAddr + VGA_BANK_SIZE] = (BYTE)CharBuffer[i * Resolution.X + j].Attributes;
1531 }
1532
1533 /* Move to the next scanline */
1534 Address += ScanlineSize;
1535 }
1536
1537 /* Return success */
1538 return TRUE;
1539 }
1540
1541 /* EOF */