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