[NTVDM]
[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 static BYTE WINAPI VgaReadPort(ULONG Port)
1008 {
1009 DPRINT("VgaReadPort: Port 0x%X\n", Port);
1010
1011 switch (Port)
1012 {
1013 case VGA_MISC_READ:
1014 return VgaMiscRegister;
1015
1016 case VGA_INSTAT0_READ:
1017 return 0; // Not implemented
1018
1019 case VGA_INSTAT1_READ_MONO:
1020 case VGA_INSTAT1_READ_COLOR:
1021 {
1022 BYTE Result = 0;
1023
1024 /* Reset the AC latch */
1025 VgaAcLatch = FALSE;
1026
1027 /* Set a flag if there is a vertical or horizontal retrace */
1028 if (InVerticalRetrace || InHorizontalRetrace) Result |= VGA_STAT_DD;
1029
1030 /* Set an additional flag if there was a vertical retrace */
1031 if (InVerticalRetrace) Result |= VGA_STAT_VRETRACE;
1032
1033 /* Clear the flags */
1034 InHorizontalRetrace = InVerticalRetrace = FALSE;
1035
1036 return Result;
1037 }
1038
1039 case VGA_FEATURE_READ:
1040 return VgaFeatureRegister;
1041
1042 case VGA_AC_INDEX:
1043 return VgaAcIndex;
1044
1045 case VGA_AC_READ:
1046 return VgaAcRegisters[VgaAcIndex];
1047
1048 case VGA_SEQ_INDEX:
1049 return VgaSeqIndex;
1050
1051 case VGA_SEQ_DATA:
1052 return VgaSeqRegisters[VgaSeqIndex];
1053
1054 case VGA_DAC_MASK:
1055 return VgaDacMask;
1056
1057 case VGA_DAC_READ_INDEX:
1058 /* This returns the read/write state */
1059 return (VgaDacReadWrite ? 0 : 3);
1060
1061 case VGA_DAC_WRITE_INDEX:
1062 return (VgaDacIndex / 3);
1063
1064 case VGA_DAC_DATA:
1065 {
1066 /* Ignore reads in write mode */
1067 if (!VgaDacReadWrite)
1068 {
1069 BYTE Data = VgaDacRegisters[VgaDacIndex++];
1070 VgaDacIndex %= VGA_PALETTE_SIZE;
1071 return Data;
1072 }
1073
1074 break;
1075 }
1076
1077 case VGA_CRTC_INDEX_MONO:
1078 case VGA_CRTC_INDEX_COLOR:
1079 return VgaCrtcIndex;
1080
1081 case VGA_CRTC_DATA_MONO:
1082 case VGA_CRTC_DATA_COLOR:
1083 return VgaCrtcRegisters[VgaCrtcIndex];
1084
1085 case VGA_GC_INDEX:
1086 return VgaGcIndex;
1087
1088 case VGA_GC_DATA:
1089 return VgaGcRegisters[VgaGcIndex];
1090
1091 default:
1092 DPRINT1("VgaReadPort: Unknown port 0x%X\n", Port);
1093 break;
1094 }
1095
1096 return 0;
1097 }
1098
1099 static VOID WINAPI VgaWritePort(ULONG Port, BYTE Data)
1100 {
1101 DPRINT("VgaWritePort: Port 0x%X, Data 0x%02X\n", Port, Data);
1102
1103 switch (Port)
1104 {
1105 case VGA_MISC_WRITE:
1106 {
1107 VgaMiscRegister = Data;
1108
1109 if (VgaMiscRegister & 0x01)
1110 {
1111 /* Color emulation */
1112 DPRINT1("Color emulation\n");
1113
1114 /* Register the new I/O Ports */
1115 RegisterIoPort(0x3D4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_COLOR
1116 RegisterIoPort(0x3D5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_COLOR
1117 RegisterIoPort(0x3DA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1118
1119 /* Unregister the old ones */
1120 UnregisterIoPort(0x3B4); // VGA_CRTC_INDEX_MONO
1121 UnregisterIoPort(0x3B5); // VGA_CRTC_DATA_MONO
1122 UnregisterIoPort(0x3BA); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1123 }
1124 else
1125 {
1126 /* Monochrome emulation */
1127 DPRINT1("Monochrome emulation\n");
1128
1129 /* Register the new I/O Ports */
1130 RegisterIoPort(0x3B4, VgaReadPort, VgaWritePort); // VGA_CRTC_INDEX_MONO
1131 RegisterIoPort(0x3B5, VgaReadPort, VgaWritePort); // VGA_CRTC_DATA_MONO
1132 RegisterIoPort(0x3BA, VgaReadPort, VgaWritePort); // VGA_INSTAT1_READ_MONO, VGA_FEATURE_WRITE_MONO
1133
1134 /* Unregister the old ones */
1135 UnregisterIoPort(0x3D4); // VGA_CRTC_INDEX_COLOR
1136 UnregisterIoPort(0x3D5); // VGA_CRTC_DATA_COLOR
1137 UnregisterIoPort(0x3DA); // VGA_INSTAT1_READ_COLOR, VGA_FEATURE_WRITE_COLOR
1138 }
1139
1140 // if (VgaMiscRegister & 0x02) { /* Enable RAM access */ } else { /* Disable RAM access */ }
1141 break;
1142 }
1143
1144 case VGA_FEATURE_WRITE_MONO:
1145 case VGA_FEATURE_WRITE_COLOR:
1146 {
1147 VgaFeatureRegister = Data;
1148 break;
1149 }
1150
1151 case VGA_AC_INDEX:
1152 // case VGA_AC_WRITE:
1153 {
1154 if (!VgaAcLatch)
1155 {
1156 /* Change the index */
1157 BYTE Index = Data & 0x1F;
1158 if (Index < VGA_AC_MAX_REG) VgaAcIndex = Index;
1159
1160 /*
1161 * Change palette protection by checking for
1162 * the Palette Address Source bit.
1163 */
1164 VgaAcPalDisable = (Data & 0x20) ? TRUE : FALSE;
1165 }
1166 else
1167 {
1168 /* Write the data */
1169 VgaWriteAc(Data);
1170 }
1171
1172 /* Toggle the latch */
1173 VgaAcLatch = !VgaAcLatch;
1174 break;
1175 }
1176
1177 case VGA_SEQ_INDEX:
1178 {
1179 /* Set the sequencer index register */
1180 if (Data < VGA_SEQ_MAX_REG) VgaSeqIndex = Data;
1181 break;
1182 }
1183
1184 case VGA_SEQ_DATA:
1185 {
1186 /* Call the sequencer function */
1187 VgaWriteSequencer(Data);
1188 break;
1189 }
1190
1191 case VGA_DAC_MASK:
1192 {
1193 VgaDacMask = Data;
1194 break;
1195 }
1196
1197 case VGA_DAC_READ_INDEX:
1198 {
1199 VgaDacReadWrite = FALSE;
1200 VgaDacIndex = Data * 3;
1201 break;
1202 }
1203
1204 case VGA_DAC_WRITE_INDEX:
1205 {
1206 VgaDacReadWrite = TRUE;
1207 VgaDacIndex = Data * 3;
1208 break;
1209 }
1210
1211 case VGA_DAC_DATA:
1212 {
1213 /* Ignore writes in read mode */
1214 if (VgaDacReadWrite) VgaWriteDac(Data & 0x3F);
1215 break;
1216 }
1217
1218 case VGA_CRTC_INDEX_MONO:
1219 case VGA_CRTC_INDEX_COLOR:
1220 {
1221 /* Set the CRTC index register */
1222 if (Data < VGA_CRTC_MAX_REG) VgaCrtcIndex = Data;
1223 break;
1224 }
1225
1226 case VGA_CRTC_DATA_MONO:
1227 case VGA_CRTC_DATA_COLOR:
1228 {
1229 /* Call the CRTC function */
1230 VgaWriteCrtc(Data);
1231 break;
1232 }
1233
1234 case VGA_GC_INDEX:
1235 {
1236 /* Set the GC index register */
1237 if (Data < VGA_GC_MAX_REG) VgaGcIndex = Data;
1238 break;
1239 }
1240
1241 case VGA_GC_DATA:
1242 {
1243 /* Call the GC function */
1244 VgaWriteGc(Data);
1245 break;
1246 }
1247
1248 default:
1249 DPRINT1("VgaWritePort: Unknown port 0x%X\n", Port);
1250 break;
1251 }
1252 }
1253
1254 /* PUBLIC FUNCTIONS ***********************************************************/
1255
1256 DWORD VgaGetVideoBaseAddress(VOID)
1257 {
1258 return MemoryBase[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
1259 }
1260
1261 DWORD VgaGetVideoLimitAddress(VOID)
1262 {
1263 return MemoryLimit[(VgaGcRegisters[VGA_GC_MISC_REG] >> 2) & 0x03];
1264 }
1265
1266 COORD VgaGetDisplayResolution(VOID)
1267 {
1268 COORD Resolution;
1269 BYTE MaximumScanLine = 1 + (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & 0x1F);
1270
1271 /* The low 8 bits are in the display registers */
1272 Resolution.X = VgaCrtcRegisters[VGA_CRTC_END_HORZ_DISP_REG];
1273 Resolution.Y = VgaCrtcRegisters[VGA_CRTC_VERT_DISP_END_REG];
1274
1275 /* Set the top bits from the overflow register */
1276 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE8)
1277 {
1278 Resolution.Y |= 1 << 8;
1279 }
1280 if (VgaCrtcRegisters[VGA_CRTC_OVERFLOW_REG] & VGA_CRTC_OVERFLOW_VDE9)
1281 {
1282 Resolution.Y |= 1 << 9;
1283 }
1284
1285 /* Increase the values by 1 */
1286 Resolution.X++;
1287 Resolution.Y++;
1288
1289 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1290 {
1291 /* Multiply the horizontal resolution by the 9/8 dot mode */
1292 Resolution.X *= (VgaSeqRegisters[VGA_SEQ_CLOCK_REG] & VGA_SEQ_CLOCK_98DM)
1293 ? 8 : 9;
1294
1295 /* The horizontal resolution is halved in 8-bit mode */
1296 if (VgaAcRegisters[VGA_AC_CONTROL_REG] & VGA_AC_CONTROL_8BIT) Resolution.X /= 2;
1297 }
1298
1299 if (VgaCrtcRegisters[VGA_CRTC_MAX_SCAN_LINE_REG] & VGA_CRTC_MAXSCANLINE_DOUBLE)
1300 {
1301 /* Halve the vertical resolution */
1302 Resolution.Y >>= 1;
1303 }
1304 else
1305 {
1306 /* Divide the vertical resolution by the maximum scan line (== font size in text mode) */
1307 Resolution.Y /= MaximumScanLine;
1308 }
1309
1310 /* Return the resolution */
1311 return Resolution;
1312 }
1313
1314 VOID VgaRefreshDisplay(VOID)
1315 {
1316 HANDLE ConsoleBufferHandle = NULL;
1317 COORD Resolution;
1318
1319 /* Set the vertical retrace flag */
1320 InVerticalRetrace = TRUE;
1321
1322 /* If nothing has changed, just return */
1323 if (!ModeChanged && !CursorMoved && !PaletteChanged && !NeedsUpdate)
1324 return;
1325
1326 /* Change the display mode */
1327 if (ModeChanged) VgaChangeMode();
1328
1329 /* Change the text cursor location */
1330 if (CursorMoved) VgaUpdateTextCursor();
1331
1332 /* Retrieve the current resolution */
1333 Resolution = VgaGetDisplayResolution();
1334
1335 if (PaletteChanged)
1336 {
1337 /* Trigger a full update of the screen */
1338 NeedsUpdate = TRUE;
1339 UpdateRectangle.Left = 0;
1340 UpdateRectangle.Top = 0;
1341 UpdateRectangle.Right = Resolution.X;
1342 UpdateRectangle.Bottom = Resolution.Y;
1343
1344 PaletteChanged = FALSE;
1345 }
1346
1347 /* Update the contents of the framebuffer */
1348 VgaUpdateFramebuffer();
1349
1350 /* Ignore if there's nothing to update */
1351 if (!NeedsUpdate) return;
1352
1353 DPRINT("Updating screen rectangle (%d, %d, %d, %d)\n",
1354 UpdateRectangle.Left,
1355 UpdateRectangle.Top,
1356 UpdateRectangle.Right,
1357 UpdateRectangle.Bottom);
1358
1359 /* Check if this is text mode or graphics mode */
1360 if (VgaGcRegisters[VGA_GC_MISC_REG] & VGA_GC_MISC_NOALPHA)
1361 {
1362 /* Graphics mode */
1363 ConsoleBufferHandle = GraphicsConsoleBuffer;
1364 }
1365 else
1366 {
1367 /* Text mode */
1368 COORD Origin = { UpdateRectangle.Left, UpdateRectangle.Top };
1369 ConsoleBufferHandle = TextConsoleBuffer;
1370
1371 /* Write the data to the console */
1372 WriteConsoleOutputA(TextConsoleBuffer,
1373 (PCHAR_INFO)ConsoleFramebuffer,
1374 Resolution,
1375 Origin,
1376 &UpdateRectangle);
1377 }
1378
1379 /* In DoubleVision mode, scale the update rectangle */
1380 if (DoubleVision)
1381 {
1382 UpdateRectangle.Left *= 2;
1383 UpdateRectangle.Top *= 2;
1384 UpdateRectangle.Right = UpdateRectangle.Right * 2 + 1;
1385 UpdateRectangle.Bottom = UpdateRectangle.Bottom * 2 + 1;
1386 }
1387
1388 /* Redraw the screen */
1389 InvalidateConsoleDIBits(ConsoleBufferHandle, &UpdateRectangle);
1390
1391 /* Clear the update flag */
1392 NeedsUpdate = FALSE;
1393 }
1394
1395 VOID VgaHorizontalRetrace(VOID)
1396 {
1397 /* Set the flag */
1398 InHorizontalRetrace = TRUE;
1399 }
1400
1401 VOID VgaReadMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
1402 {
1403 DWORD i;
1404 DWORD VideoAddress;
1405
1406 DPRINT("VgaReadMemory: Address 0x%08X, Size %lu\n", Address, Size);
1407
1408 /* Ignore if video RAM access is disabled */
1409 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1410
1411 /* Loop through each byte */
1412 for (i = 0; i < Size; i++)
1413 {
1414 VideoAddress = VgaTranslateReadAddress(Address + i);
1415
1416 /* Load the latch registers */
1417 VgaLatchRegisters[0] = VgaMemory[LOWORD(VideoAddress)];
1418 VgaLatchRegisters[1] = VgaMemory[VGA_BANK_SIZE + LOWORD(VideoAddress)];
1419 VgaLatchRegisters[2] = VgaMemory[(2 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1420 VgaLatchRegisters[3] = VgaMemory[(3 * VGA_BANK_SIZE) + LOWORD(VideoAddress)];
1421
1422 /* Copy the value to the buffer */
1423 Buffer[i] = VgaMemory[VideoAddress];
1424 }
1425 }
1426
1427 VOID VgaWriteMemory(DWORD Address, LPBYTE Buffer, DWORD Size)
1428 {
1429 DWORD i, j;
1430 DWORD VideoAddress;
1431
1432 DPRINT("VgaWriteMemory: Address 0x%08X, Size %lu\n", Address, Size);
1433
1434 /* Ignore if video RAM access is disabled */
1435 if ((VgaMiscRegister & VGA_MISC_RAM_ENABLED) == 0) return;
1436
1437 /* Also ignore if write access to all planes is disabled */
1438 if ((VgaSeqRegisters[VGA_SEQ_MASK_REG] & 0x0F) == 0x00) return;
1439
1440 /* Loop through each byte */
1441 for (i = 0; i < Size; i++)
1442 {
1443 VideoAddress = VgaTranslateWriteAddress(Address + i);
1444
1445 for (j = 0; j < VGA_NUM_BANKS; j++)
1446 {
1447 /* Make sure the page is writeable */
1448 if (!(VgaSeqRegisters[VGA_SEQ_MASK_REG] & (1 << j))) continue;
1449
1450 /* Check if this is chain-4 mode */
1451 if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4)
1452 {
1453 if (((Address + i) & 3) != j)
1454 {
1455 /* This plane will not be accessed */
1456 continue;
1457 }
1458 }
1459
1460 /* Check if this is odd-even mode */
1461 if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE)
1462 {
1463 if (((Address + i) & 1) != (j & 1))
1464 {
1465 /* This plane will not be accessed */
1466 continue;
1467 }
1468 }
1469
1470 /* Copy the value to the VGA memory */
1471 VgaMemory[VideoAddress + j * VGA_BANK_SIZE] = VgaTranslateByteForWriting(Buffer[i], j);
1472 }
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 */