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