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