sync to trunk head (35945)
[reactos.git] / reactos / drivers / base / bootvid / i386 / bootvid.c
1 #include "precomp.h"
2
3 /* PRIVATE FUNCTIONS *********************************************************/
4
5 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 /* The port is what is in the stream right now */
140 ShortPort = UlongToPtr(*CmdStream);
141
142 /* Move to the next command and get the count */
143 Count = *(CmdStream++);
144
145 /* Move to the next command and get the value to write */
146 ShortValue = *(CmdStream++);
147
148 /* Add the base to the port */
149 ShortPort = PtrToUlong(ShortPort) + (PUSHORT)Base;
150
151 /* Move to next command */
152 CmdStream++;
153
154 /* Make sure we have data */
155 if (!ShortValue) continue;
156
157 /* Loop the cmd array */
158 for (; Count; Count--, CmdStream++, Value++)
159 {
160 /* Get the byte we're writing */
161 ShortValue += (*CmdStream) << 8;
162
163 /* Write USHORT to the port */
164 WRITE_PORT_USHORT(ShortPort, ShortValue);
165 }
166 break;
167 case 1:
168 /* The port is what is in the stream right now. Add the base too */
169 Port = *CmdStream + Base;
170
171 /* Move to the next command and get the count */
172 Count = *++CmdStream;
173
174 /* Move to the next command and get the index to write */
175 Index = (UCHAR)*++CmdStream;
176
177 /* Move to next command */
178 CmdStream++;
179
180 /* Loop the cmd array */
181 for (; Count; Count--, Index++)
182 {
183 /* Write the index */
184 WRITE_PORT_UCHAR(Port, Index);
185
186 /* Get the byte we're writing */
187 Value = (UCHAR)*CmdStream;
188
189 /* Move to next command */
190 CmdStream++;
191
192 /* Write UCHAR value to the port */
193 WRITE_PORT_UCHAR(Port, Value);
194 }
195 break;
196 case 2:
197 /* The port is what is in the stream right now. Add the base too */
198 Port = *CmdStream + Base;
199
200 /* Read the current value and add the stream data */
201 Value = READ_PORT_UCHAR(Port);
202 Value &= *CmdStream++;
203 Value ^= *CmdStream++;
204
205 /* Write the value */
206 WRITE_PORT_UCHAR(Port, Value);
207 break;
208 default:
209 /* Unknown command, fail */
210 return FALSE;
211 }
212 }
213 else if (Major != 0xF0)
214 {
215 /* Unknown major function, fail */
216 return FALSE;
217 }
218
219 /* Get the next command */
220 Cmd = *CmdStream;
221 }
222
223 /* If we got here, return success */
224 return TRUE;
225 }
226
227 BOOLEAN
228 NTAPI
229 VgaIsPresent(VOID)
230 {
231 UCHAR VgaReg, VgaReg2, VgaReg3;
232 UCHAR SeqReg, SeqReg2;
233 UCHAR i;
234
235 /* Read the VGA Address Register */
236 VgaReg = READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE);
237
238 /* Select Read Map Select Register */
239 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 4);
240
241 /* Read it back...it should be 4 */
242 if (((READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE)) & 0xF) != 4) return FALSE;
243
244 /* Read the VGA Data Register */
245 VgaReg2 = READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF);
246
247 /* Enable all planes */
248 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 3);
249
250 /* Read it back...it should be 3 */
251 if (READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF) != 0x3)
252 {
253 /* Reset the registers and fail */
254 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 0);
255 return FALSE;
256 }
257
258 /* Select Bit Mask Register */
259 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 8);
260
261 /* Read it back...it should be 8 */
262 if (((READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE)) & 0xF) != 8)
263 {
264 /* Reset the registers and fail */
265 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 4);
266 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 0);
267 return FALSE;
268 }
269
270 /* Read the VGA Data Register */
271 VgaReg3 = READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF);
272
273 /* Loop bitmasks */
274 for (i = 0xBB; i; i >>= 1)
275 {
276 /* Set bitmask */
277 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, i);
278
279 /* Read it back...it should be the same */
280 if (READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF) != i)
281 {
282 /* Reset the registers and fail */
283 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 0xFF);
284 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 4);
285 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 0);
286 return FALSE;
287 }
288 }
289
290 /* Select Read Map Select Register */
291 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 4);
292
293 /* Read it back...it should be 3 */
294 if (READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF) != 3)
295 {
296 /* Reset the registers and fail */
297 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 0);
298 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 8);
299 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, 0xFF);
300 return FALSE;
301 }
302
303 /* Write the registers we read earlier */
304 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, VgaReg2);
305 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, 8);
306 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CF, VgaReg3);
307 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3CE, VgaReg);
308
309 /* Read sequencer address */
310 SeqReg = READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C4);
311
312 /* Select memory mode register */
313 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C4, 4);
314
315 /* Read it back...it should still be 4 */
316 if (((READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C4)) & 7) != 4)
317 {
318 /* Fail */
319 return FALSE;
320 }
321
322 /* Read sequencer Data */
323 SeqReg2 = READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C5);
324
325 /* Write null plane */
326 WRITE_PORT_USHORT((PUSHORT)VgaRegisterBase + 0x3C4, 0x100);
327
328 /* Write sequencer flag */
329 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C5, SeqReg2 ^ 8);
330
331 /* Read it back */
332 if ((READ_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C5)) != (SeqReg2 ^ 8))
333 {
334 /* Not the same value...restore registers and fail */
335 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C5, 2);
336 WRITE_PORT_USHORT((PUSHORT)VgaRegisterBase + 0x3C4, 0x300);
337 return FALSE;
338 }
339
340 /* Now write the registers we read */
341 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C5, SeqReg2);
342 WRITE_PORT_USHORT((PUSHORT)VgaRegisterBase + 0x3C4, 0x300);
343 WRITE_PORT_UCHAR((PUCHAR)VgaRegisterBase + 0x3C4, SeqReg);
344
345 /* VGA is present! */
346 return TRUE;
347 }
348
349 /* PUBLIC FUNCTIONS **********************************************************/
350
351 /*
352 * @implemented
353 */
354 BOOLEAN
355 NTAPI
356 VidInitialize(IN BOOLEAN SetMode)
357 {
358 ULONG_PTR Context = 0;
359 PHYSICAL_ADDRESS TranslatedAddress;
360 PHYSICAL_ADDRESS NullAddress = {{0}};
361 ULONG AddressSpace = 1;
362 BOOLEAN Result;
363 ULONG_PTR Base;
364
365 /* Make sure that we have a bus translation function */
366 if (!HalFindBusAddressTranslation) return FALSE;
367
368 /* Get the VGA Register address */
369 Result = HalFindBusAddressTranslation(NullAddress,
370 &AddressSpace,
371 &TranslatedAddress,
372 &Context,
373 TRUE);
374 if (!Result) return FALSE;
375
376 /* See if this is I/O Space, which we need to map */
377 TryAgain:
378 if (!AddressSpace)
379 {
380 /* Map it */
381 Base = (ULONG_PTR)MmMapIoSpace(TranslatedAddress, 0x400, MmNonCached);
382 }
383 else
384 {
385 /* The base is the translated address, no need to map I/O space */
386 Base = TranslatedAddress.LowPart;
387 }
388
389 /* Set the VGA Register base and now check if we have a VGA device */
390 VgaRegisterBase = Base;
391 if (VgaIsPresent())
392 {
393 /* Translate the VGA Memory Address */
394 NullAddress.LowPart = 0xA0000;
395 AddressSpace = 0;
396 Result = HalFindBusAddressTranslation(NullAddress,
397 &AddressSpace,
398 &TranslatedAddress,
399 &Context,
400 FALSE);
401 if (Result)
402 {
403 /* Success! See if this is I/O Space, which we need to map */
404 if (!AddressSpace)
405 {
406 /* Map it */
407 Base = (ULONG_PTR)MmMapIoSpace(TranslatedAddress,
408 0x20000,
409 MmNonCached);
410 }
411 else
412 {
413 /* The base is the translated address, no need to map I/O space */
414 Base = TranslatedAddress.LowPart;
415 }
416
417 /* Set the VGA Memory Base */
418 VgaBase = Base;
419
420 /* Now check if we have to set the mode */
421 if (SetMode)
422 {
423 /* Reset the display */
424 HalResetDisplay();
425 curr_x = 0;
426 curr_y = 0;
427
428 /* Initialize it */
429 VgaInterpretCmdStream(AT_Initialization);
430 return TRUE;
431 }
432 }
433 }
434 else
435 {
436 /* It's not, so unmap the I/O space if we mapped it */
437 if (!AddressSpace) MmUnmapIoSpace((PVOID)VgaRegisterBase, 0x400);
438 }
439
440 /* If we got here, then we failed...let's try again */
441 Result = HalFindBusAddressTranslation(NullAddress,
442 &AddressSpace,
443 &TranslatedAddress,
444 &Context,
445 TRUE);
446 if (Result) goto TryAgain;
447
448 /* If we got here, then we failed even past our re-try... */
449 return FALSE;
450 }
451
452 /*
453 * @implemented
454 */
455 VOID
456 NTAPI
457 VidResetDisplay(IN BOOLEAN HalReset)
458 {
459 /* Clear the current position */
460 curr_x = 0;
461 curr_y = 0;
462
463 /* Clear the screen with HAL if we were asked to */
464 if (HalReset) HalResetDisplay();
465
466 /* Re-initialize the VGA Display */
467 VgaInterpretCmdStream(AT_Initialization);
468
469 /* Re-initialize the palette and fill the screen black */
470 InitializePalette();
471 VidSolidColorFill(0, 0, 639, 479, 0);
472 }
473