[BOOTVID] Fixes for VgaIsPresent() and VidInitialize().
[reactos.git] / drivers / base / bootvid / i386 / bootvid.c
1 #include "precomp.h"
2
3 /* PRIVATE FUNCTIONS *********************************************************/
4
5 static BOOLEAN
6 NTAPI
7 VgaInterpretCmdStream(IN PUSHORT CmdStream)
8 {
9 PUCHAR Base = (PUCHAR)VgaRegisterBase;
10 USHORT Cmd;
11 UCHAR Major, Minor;
12 USHORT Count;
13 UCHAR Index;
14 PUSHORT Buffer;
15 PUSHORT ShortPort;
16 PUCHAR Port;
17 UCHAR Value;
18 USHORT ShortValue;
19
20 /* First make sure that we have a Command Stream */
21 if (!CmdStream) return TRUE;
22
23 /* Loop as long as we have commands */
24 while (*CmdStream)
25 {
26 /* Get the Major and Minor Function */
27 Cmd = *CmdStream;
28 Major = Cmd & 0xF0;
29 Minor = Cmd & 0x0F;
30
31 /* Move to the next command */
32 CmdStream++;
33
34 /* Check which major function this was */
35 if (Major == 0x10)
36 {
37 /* Now let's see the minor function */
38 if (Minor & CMD_STREAM_READ)
39 {
40 /* Now check the sub-type */
41 if (Minor & CMD_STREAM_USHORT)
42 {
43 /* The port is what is in the stream right now */
44 ShortPort = UlongToPtr((ULONG)*CmdStream);
45
46 /* Move to the next command */
47 CmdStream++;
48
49 /* Read USHORT from the port */
50 READ_PORT_USHORT(PtrToUlong(Base) + ShortPort);
51 }
52 else
53 {
54 /* The port is what is in the stream right now */
55 Port = UlongToPtr((ULONG)*CmdStream);
56
57 /* Move to the next command */
58 CmdStream++;
59
60 /* Read UCHAR from the port */
61 READ_PORT_UCHAR(PtrToUlong(Base) + Port);
62 }
63 }
64 else if (Minor & CMD_STREAM_WRITE_ARRAY)
65 {
66 /* Now check the sub-type */
67 if (Minor & CMD_STREAM_USHORT)
68 {
69 /* The port is what is in the stream right now */
70 ShortPort = UlongToPtr(Cmd);
71
72 /* Move to the next command and get the count */
73 Count = *(CmdStream++);
74
75 /* The buffer is what's next in the command stream */
76 Buffer = CmdStream++;
77
78 /* Write USHORT to the port */
79 WRITE_PORT_BUFFER_USHORT(PtrToUshort(Base) + ShortPort, Buffer, Count);
80
81 /* Move past the buffer in the command stream */
82 CmdStream += Count;
83 }
84 else
85 {
86 /* The port is what is in the stream right now */
87 Port = UlongToPtr(Cmd);
88
89 /* Move to the next command and get the count */
90 Count = *(CmdStream++);
91
92 /* Add the base to the port */
93 Port = PtrToUlong(Port) + Base;
94
95 /* Move to next command */
96 CmdStream++;
97
98 /* Loop the cmd array */
99 for (; Count; Count--, CmdStream++)
100 {
101 /* Get the byte we're writing */
102 Value = (UCHAR)*CmdStream;
103
104 /* Write UCHAR to the port */
105 WRITE_PORT_UCHAR(Port, Value);
106 }
107 }
108 }
109 else if (Minor & CMD_STREAM_USHORT)
110 {
111 /* Get the ushort we're writing and advance in the stream */
112 ShortValue = *CmdStream;
113 CmdStream++;
114
115 /* Write USHORT to the port (which is in cmd) */
116 WRITE_PORT_USHORT((PUSHORT)Base + Cmd, ShortValue);
117 }
118 else
119 {
120 /* The port is what is in the stream right now */
121 Port = UlongToPtr((ULONG)*CmdStream);
122
123 /* Get the uchar we're writing */
124 Value = (UCHAR)*++CmdStream;
125
126 /* Move to the next command */
127 CmdStream++;
128
129 /* Write UCHAR to the port (which is in cmd) */
130 WRITE_PORT_UCHAR(PtrToUlong(Base) + Port, Value);
131 }
132 }
133 else if (Major == 0x20)
134 {
135 /* Check the minor function. Note these are not flags anymore. */
136 switch (Minor)
137 {
138 case 0:
139 {
140 /* The port is what is in the stream right now */
141 ShortPort = UlongToPtr(*CmdStream);
142
143 /* Move to the next command and get the count */
144 Count = *(CmdStream++);
145
146 /* Move to the next command and get the value to write */
147 ShortValue = *(CmdStream++);
148
149 /* Add the base to the port */
150 ShortPort = PtrToUlong(ShortPort) + (PUSHORT)Base;
151
152 /* Move to next command */
153 CmdStream++;
154
155 /* Make sure we have data */
156 if (!ShortValue) continue;
157
158 /* Loop the cmd array */
159 for (; Count; Count--, CmdStream++)
160 {
161 /* Get the byte we're writing */
162 ShortValue += (*CmdStream) << 8;
163
164 /* Write USHORT to the port */
165 WRITE_PORT_USHORT(ShortPort, ShortValue);
166 }
167 break;
168 }
169
170 case 1:
171 {
172 /* The port is what is in the stream right now. Add the base too */
173 Port = *CmdStream + Base;
174
175 /* Move to the next command and get the count */
176 Count = *++CmdStream;
177
178 /* Move to the next command and get the index to write */
179 Index = (UCHAR)*++CmdStream;
180
181 /* Move to next command */
182 CmdStream++;
183
184 /* Loop the cmd array */
185 for (; Count; Count--, Index++)
186 {
187 /* Write the index */
188 WRITE_PORT_UCHAR(Port, Index);
189
190 /* Get the byte we're writing */
191 Value = (UCHAR)*CmdStream;
192
193 /* Move to next command */
194 CmdStream++;
195
196 /* Write UCHAR value to the port */
197 WRITE_PORT_UCHAR(Port, Value);
198 }
199 break;
200 }
201
202 case 2:
203 {
204 /* The port is what is in the stream right now. Add the base too */
205 Port = *CmdStream + Base;
206
207 /* Read the current value and add the stream data */
208 Value = READ_PORT_UCHAR(Port);
209 Value &= *CmdStream++;
210 Value ^= *CmdStream++;
211
212 /* Write the value */
213 WRITE_PORT_UCHAR(Port, Value);
214 break;
215 }
216
217 default:
218 /* Unknown command, fail */
219 return FALSE;
220 }
221 }
222 else if (Major != 0xF0)
223 {
224 /* Unknown major function, fail */
225 return FALSE;
226 }
227 }
228
229 /* If we got here, return success */
230 return TRUE;
231 }
232
233 static BOOLEAN
234 NTAPI
235 VgaIsPresent(VOID)
236 {
237 UCHAR VgaReg, VgaReg2, VgaReg3;
238 UCHAR SeqReg, SeqReg2;
239 UCHAR i;
240
241 /* Read the VGA Address Register */
242 VgaReg = __inpb(0x3CE);
243
244 /* Select Read Map Select Register */
245 __outpb(0x3CE, 4);
246
247 /* Read it back... it should be 4 */
248 if ((__inpb(0x3CE) & 0xF) != 4)
249 return FALSE;
250
251 /* Read the VGA Data Register */
252 VgaReg2 = __inpb(0x3CF);
253
254 /* Enable all planes */
255 __outpb(0x3CF, 3);
256
257 /* Read it back... it should be 3 */
258 if (__inpb(0x3CF) != 0x3)
259 {
260 /* Reset the registers and fail */
261 __outpb(0x3CF, 0);
262 return FALSE;
263 }
264
265 /* Select Bit Mask Register */
266 __outpb(0x3CE, 8);
267
268 /* Read it back... it should be 8 */
269 if ((__inpb(0x3CE) & 0xF) != 8)
270 {
271 /* Reset the registers and fail */
272 __outpb(0x3CE, 4);
273 __outpb(0x3CF, 0);
274 return FALSE;
275 }
276
277 /* Read the VGA Data Register */
278 VgaReg3 = __inpb(0x3CF);
279
280 /* Loop bitmasks */
281 for (i = 0xBB; i; i >>= 1)
282 {
283 /* Set bitmask */
284 __outpb(0x3CF, i);
285
286 /* Read it back... it should be the same */
287 if (__inpb(0x3CF) != i)
288 {
289 /* Reset the registers and fail */
290 __outpb(0x3CF, 0xFF);
291 __outpb(0x3CE, 4);
292 __outpb(0x3CF, 0);
293 return FALSE;
294 }
295 }
296
297 /* Select Read Map Select Register */
298 __outpb(0x3CE, 4);
299
300 /* Read it back... it should be 3 */
301 if (__inpb(0x3CF) != 3)
302 {
303 /* Reset the registers and fail */
304 __outpb(0x3CF, 0);
305 __outpb(0x3CE, 8);
306 __outpb(0x3CF, 0xFF);
307 return FALSE;
308 }
309
310 /* Write the registers we read earlier */
311 __outpb(0x3CF, VgaReg2);
312 __outpb(0x3CE, 8);
313 __outpb(0x3CF, VgaReg3);
314 __outpb(0x3CE, VgaReg);
315
316 /* Read sequencer address */
317 SeqReg = __inpb(0x3C4);
318
319 /* Select memory mode register */
320 __outpb(0x3C4, 4);
321
322 /* Read it back... it should still be 4 */
323 if ((__inpb(0x3C4) & 7) != 4)
324 {
325 /* Fail */
326 return FALSE;
327 }
328
329 /* Read sequencer Data */
330 SeqReg2 = __inpb(0x3C5);
331
332 /* Write null plane */
333 __outpw(0x3C4, 0x100);
334
335 /* Select memory mode register */
336 __outpb(0x3C4, 4);
337
338 /* Write sequencer flag */
339 __outpb(0x3C5, SeqReg2 ^ 8);
340
341 /* Read it back */
342 if (__inpb(0x3C5) != (SeqReg2 ^ 8))
343 {
344 /* Not the same value... restore registers and fail */
345 __outpb(0x3C5, 2);
346 __outpw(0x3C4, 0x300);
347 return FALSE;
348 }
349
350 /* Now write the registers we read */
351 __outpb(0x3C5, SeqReg2);
352 __outpw(0x3C4, 0x300);
353 __outpb(0x3C4, SeqReg);
354
355 /* VGA is present! */
356 return TRUE;
357 }
358
359 /* PUBLIC FUNCTIONS **********************************************************/
360
361 /*
362 * @implemented
363 */
364 BOOLEAN
365 NTAPI
366 VidInitialize(IN BOOLEAN SetMode)
367 {
368 ULONG_PTR Context = 0;
369 PHYSICAL_ADDRESS TranslatedAddress;
370 PHYSICAL_ADDRESS NullAddress = {{0, 0}}, VgaAddress;
371 ULONG AddressSpace;
372 BOOLEAN Result;
373 ULONG_PTR Base;
374
375 /* Make sure that we have a bus translation function */
376 if (!HalFindBusAddressTranslation) return FALSE;
377
378 /* Loop trying to find possible VGA base addresses */
379 while (TRUE)
380 {
381 /* Get the VGA Register address */
382 AddressSpace = 1;
383 Result = HalFindBusAddressTranslation(NullAddress,
384 &AddressSpace,
385 &TranslatedAddress,
386 &Context,
387 TRUE);
388 if (!Result) return FALSE;
389
390 /* See if this is I/O Space, which we need to map */
391 if (!AddressSpace)
392 {
393 /* Map it */
394 Base = (ULONG_PTR)MmMapIoSpace(TranslatedAddress, 0x400, MmNonCached);
395 }
396 else
397 {
398 /* The base is the translated address, no need to map I/O space */
399 Base = TranslatedAddress.LowPart;
400 }
401
402 /* Try to see if this is VGA */
403 VgaRegisterBase = Base;
404 if (VgaIsPresent())
405 {
406 /* Translate the VGA Memory Address */
407 VgaAddress.LowPart = 0xA0000;
408 VgaAddress.HighPart = 0;
409 AddressSpace = 0;
410 Result = HalFindBusAddressTranslation(VgaAddress,
411 &AddressSpace,
412 &TranslatedAddress,
413 &Context,
414 FALSE);
415 if (Result) break;
416 }
417 else
418 {
419 /* It's not, so unmap the I/O space if we mapped it */
420 if (!AddressSpace) MmUnmapIoSpace((PVOID)VgaRegisterBase, 0x400);
421 }
422
423 /* Continue trying to see if there's any other address */
424 }
425
426 /* Success! See if this is I/O Space, which we need to map */
427 if (!AddressSpace)
428 {
429 /* Map it */
430 Base = (ULONG_PTR)MmMapIoSpace(TranslatedAddress,
431 0x20000,
432 MmNonCached);
433 }
434 else
435 {
436 /* The base is the translated address, no need to map I/O space */
437 Base = TranslatedAddress.LowPart;
438 }
439
440 /* Set the VGA Memory Base */
441 VgaBase = Base;
442
443 /* Now check if we have to set the mode */
444 if (SetMode)
445 {
446 /* Reset the display */
447 HalResetDisplay();
448 curr_x = 0;
449 curr_y = 0;
450
451 /* Initialize it */
452 VgaInterpretCmdStream(AT_Initialization);
453 }
454
455 /* VGA is ready */
456 return TRUE;
457 }
458
459 /*
460 * @implemented
461 */
462 VOID
463 NTAPI
464 VidResetDisplay(IN BOOLEAN HalReset)
465 {
466 /* Clear the current position */
467 curr_x = 0;
468 curr_y = 0;
469
470 /* Clear the screen with HAL if we were asked to */
471 if (HalReset) HalResetDisplay();
472
473 /* Re-initialize the VGA Display */
474 VgaInterpretCmdStream(AT_Initialization);
475
476 /* Re-initialize the palette and fill the screen black */
477 InitializePalette();
478 VidSolidColorFill(0, 0, 639, 479, 0);
479 }