1 #include "precomp.h" 2 3 /* PRIVATE FUNCTIONS *********************************************************/ 4 5 static BOOLEAN 6 NTAPI 7 VgaInterpretCmdStream( 8 _In_ PUSHORT CmdStream) 9 { 10 USHORT Cmd; 11 UCHAR Major, Minor; 12 USHORT Port; 13 USHORT Count; 14 UCHAR Index; 15 UCHAR Value; 16 USHORT ShortValue; 17 18 /* First make sure that we have a Command Stream */ 19 if (!CmdStream) return TRUE; 20 21 /* Loop as long as we have commands */ 22 while (*CmdStream != EOD) 23 { 24 /* Get the next command and its Major and Minor functions */ 25 Cmd = *CmdStream++; 26 Major = Cmd & 0xF0; 27 Minor = Cmd & 0x0F; 28 29 /* Check which major function this is */ 30 if (Major == INOUT) 31 { 32 /* Check the minor function */ 33 if (Minor & IO /* CMD_STREAM_READ */) 34 { 35 /* Check the sub-type */ 36 if (Minor & BW /* CMD_STREAM_USHORT */) 37 { 38 /* Get the port and read an USHORT from it */ 39 Port = *CmdStream++; 40 ShortValue = __inpw(Port); 41 } 42 else // if (Minor & CMD_STREAM_WRITE) 43 { 44 /* Get the port and read an UCHAR from it */ 45 Port = *CmdStream++; 46 Value = __inpb(Port); 47 } 48 } 49 else if (Minor & MULTI /* CMD_STREAM_WRITE_ARRAY */) 50 { 51 /* Check the sub-type */ 52 if (Minor & BW /* CMD_STREAM_USHORT */) 53 { 54 /* Get the port and the count of elements */ 55 Port = *CmdStream++; 56 Count = *CmdStream++; 57 58 /* Write the USHORT to the port; the buffer is what's in the command stream */ 59 WRITE_PORT_BUFFER_USHORT((PUSHORT)(VgaRegisterBase + Port), CmdStream, Count); 60 61 /* Move past the buffer in the command stream */ 62 CmdStream += Count; 63 } 64 else // if (Minor & CMD_STREAM_WRITE) 65 { 66 /* Get the port and the count of elements */ 67 Port = *CmdStream++; 68 Count = *CmdStream++; 69 70 /* Loop the command array */ 71 for (; Count; --Count, ++CmdStream) 72 { 73 /* Get the UCHAR and write it to the port */ 74 Value = (UCHAR)*CmdStream; 75 __outpb(Port, Value); 76 } 77 } 78 } 79 else if (Minor & BW /* CMD_STREAM_USHORT */) 80 { 81 /* Get the port */ 82 Port = *CmdStream++; 83 84 /* Get the USHORT and write it to the port */ 85 ShortValue = *CmdStream++; 86 __outpw(Port, ShortValue); 87 } 88 else // if (Minor & CMD_STREAM_WRITE) 89 { 90 /* Get the port */ 91 Port = *CmdStream++; 92 93 /* Get the UCHAR and write it to the port */ 94 Value = (UCHAR)*CmdStream++; 95 __outpb(Port, Value); 96 } 97 } 98 else if (Major == METAOUT) 99 { 100 /* Check the minor function. Note these are not flags. */ 101 switch (Minor) 102 { 103 case INDXOUT: 104 { 105 /* Get the port, the count of elements and the start index */ 106 Port = *CmdStream++; 107 Count = *CmdStream++; 108 Index = (UCHAR)*CmdStream++; 109 110 /* Loop the command array */ 111 for (; Count; --Count, ++Index, ++CmdStream) 112 { 113 /* Get the USHORT and write it to the port */ 114 ShortValue = (USHORT)Index + ((*CmdStream) << 8); 115 __outpw(Port, ShortValue); 116 } 117 break; 118 } 119 120 case ATCOUT: 121 { 122 /* Get the port, the count of elements and the start index */ 123 Port = *CmdStream++; 124 Count = *CmdStream++; 125 Index = (UCHAR)*CmdStream++; 126 127 /* Loop the command array */ 128 for (; Count; --Count, ++Index, ++CmdStream) 129 { 130 /* Write the index */ 131 __outpb(Port, Index); 132 133 /* Get the UCHAR and write it to the port */ 134 Value = (UCHAR)*CmdStream; 135 __outpb(Port, Value); 136 } 137 break; 138 } 139 140 case MASKOUT: 141 { 142 /* Get the port */ 143 Port = *CmdStream++; 144 145 /* Read the current value and add the stream data */ 146 Value = __inpb(Port); 147 Value &= *CmdStream++; 148 Value ^= *CmdStream++; 149 150 /* Write the value */ 151 __outpb(Port, Value); 152 break; 153 } 154 155 default: 156 /* Unknown command, fail */ 157 return FALSE; 158 } 159 } 160 else if (Major != NCMD) 161 { 162 /* Unknown major function, fail */ 163 return FALSE; 164 } 165 } 166 167 /* If we got here, return success */ 168 return TRUE; 169 } 170 171 static BOOLEAN 172 NTAPI 173 VgaIsPresent(VOID) 174 { 175 UCHAR OrgGCAddr, OrgReadMap, OrgBitMask; 176 UCHAR OrgSCAddr, OrgMemMode; 177 UCHAR i; 178 179 /* Remember the original state of the Graphics Controller Address register */ 180 OrgGCAddr = __inpb(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT); 181 182 /* 183 * Write the Read Map register with a known state so we can verify 184 * that it isn't changed after we fool with the Bit Mask. This ensures 185 * that we're dealing with indexed registers, since both the Read Map and 186 * the Bit Mask are addressed at GRAPH_DATA_PORT. 187 */ 188 __outpb(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, IND_READ_MAP); 189 190 /* 191 * If we can't read back the Graphics Address register setting we just 192 * performed, it's not readable and this isn't a VGA. 193 */ 194 if ((__inpb(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT) & GRAPH_ADDR_MASK) != IND_READ_MAP) 195 return FALSE; 196 197 /* 198 * Set the Read Map register to a known state. 199 */ 200 OrgReadMap = __inpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT); 201 __outpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT, READ_MAP_TEST_SETTING); 202 203 /* Read it back... it should be the same */ 204 if (__inpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT) != READ_MAP_TEST_SETTING) 205 { 206 /* 207 * The Read Map setting we just performed can't be read back; not a 208 * VGA. Restore the default Read Map state and fail. 209 */ 210 __outpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT, READ_MAP_DEFAULT); 211 return FALSE; 212 } 213 214 /* Remember the original setting of the Bit Mask register */ 215 __outpb(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, IND_BIT_MASK); 216 217 /* Read it back... it should be the same */ 218 if ((__inpb(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT) & GRAPH_ADDR_MASK) != IND_BIT_MASK) 219 { 220 /* 221 * The Graphics Address register setting we just made can't be read 222 * back; not a VGA. Restore the default Read Map state and fail. 223 */ 224 __outpb(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, IND_READ_MAP); 225 __outpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT, READ_MAP_DEFAULT); 226 return FALSE; 227 } 228 229 /* Read the VGA Data Register */ 230 OrgBitMask = __inpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT); 231 232 /* 233 * Set up the initial test mask we'll write to and read from the Bit Mask, 234 * and loop on the bitmasks. 235 */ 236 for (i = 0xBB; i; i >>= 1) 237 { 238 /* Write the test mask to the Bit Mask */ 239 __outpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT, i); 240 241 /* Read it back... it should be the same */ 242 if (__inpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT) != i) 243 { 244 /* 245 * The Bit Mask is not properly writable and readable; not a VGA. 246 * Restore the Bit Mask and Read Map to their default states and fail. 247 */ 248 __outpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT, BIT_MASK_DEFAULT); 249 __outpb(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, IND_READ_MAP); 250 __outpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT, READ_MAP_DEFAULT); 251 return FALSE; 252 } 253 } 254 255 /* 256 * There's something readable at GRAPH_DATA_PORT; now switch back and 257 * make sure that the Read Map register hasn't changed, to verify that 258 * we're dealing with indexed registers. 259 */ 260 __outpb(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, IND_READ_MAP); 261 262 /* Read it back */ 263 if (__inpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT) != READ_MAP_TEST_SETTING) 264 { 265 /* 266 * The Read Map is not properly writable and readable; not a VGA. 267 * Restore the Bit Mask and Read Map to their default states, in case 268 * this is an EGA, so subsequent writes to the screen aren't garbled. 269 * Then fail. 270 */ 271 __outpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT, READ_MAP_DEFAULT); 272 __outpb(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, IND_BIT_MASK); 273 __outpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT, BIT_MASK_DEFAULT); 274 return FALSE; 275 } 276 277 /* 278 * We've pretty surely verified the existence of the Bit Mask register. 279 * Put the Graphics Controller back to the original state. 280 */ 281 __outpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT, OrgReadMap); 282 __outpb(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, IND_BIT_MASK); 283 __outpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT, OrgBitMask); 284 __outpb(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, OrgGCAddr); 285 286 /* 287 * Now, check for the existence of the Chain4 bit. 288 */ 289 290 /* 291 * Remember the original states of the Sequencer Address and Memory Mode 292 * registers. 293 */ 294 OrgSCAddr = __inpb(VGA_BASE_IO_PORT + SEQ_ADDRESS_PORT); 295 __outpb(VGA_BASE_IO_PORT + SEQ_ADDRESS_PORT, IND_MEMORY_MODE); 296 297 /* Read it back... it should be the same */ 298 if ((__inpb(VGA_BASE_IO_PORT + SEQ_ADDRESS_PORT) & SEQ_ADDR_MASK) != IND_MEMORY_MODE) 299 { 300 /* 301 * Couldn't read back the Sequencer Address register setting 302 * we just performed, fail. 303 */ 304 return FALSE; 305 } 306 307 /* Read sequencer Data */ 308 OrgMemMode = __inpb(VGA_BASE_IO_PORT + SEQ_DATA_PORT); 309 310 /* 311 * Toggle the Chain4 bit and read back the result. This must be done during 312 * sync reset, since we're changing the chaining state. 313 */ 314 315 /* Begin sync reset */ 316 __outpw(VGA_BASE_IO_PORT + SEQ_ADDRESS_PORT, (IND_SYNC_RESET + (START_SYNC_RESET_VALUE << 8))); 317 318 /* Toggle the Chain4 bit */ 319 __outpb(VGA_BASE_IO_PORT + SEQ_ADDRESS_PORT, IND_MEMORY_MODE); 320 __outpb(VGA_BASE_IO_PORT + SEQ_DATA_PORT, OrgMemMode ^ CHAIN4_MASK); 321 322 /* Read it back... it should be the same */ 323 if (__inpb(VGA_BASE_IO_PORT + SEQ_DATA_PORT) != (OrgMemMode ^ CHAIN4_MASK)) 324 { 325 /* 326 * Chain4 bit is not there, not a VGA. 327 * Set text mode default for Memory Mode register. 328 */ 329 __outpb(VGA_BASE_IO_PORT + SEQ_DATA_PORT, MEMORY_MODE_TEXT_DEFAULT); 330 331 /* End sync reset */ 332 __outpw(VGA_BASE_IO_PORT + SEQ_ADDRESS_PORT, (IND_SYNC_RESET + (END_SYNC_RESET_VALUE << 8))); 333 334 /* Fail */ 335 return FALSE; 336 } 337 338 /* 339 * It's a VGA. 340 */ 341 342 /* Restore the original Memory Mode setting */ 343 __outpb(VGA_BASE_IO_PORT + SEQ_DATA_PORT, OrgMemMode); 344 345 /* End sync reset */ 346 __outpw(VGA_BASE_IO_PORT + SEQ_ADDRESS_PORT, (IND_SYNC_RESET + (END_SYNC_RESET_VALUE << 8))); 347 348 /* Restore the original Sequencer Address setting */ 349 __outpb(VGA_BASE_IO_PORT + SEQ_ADDRESS_PORT, OrgSCAddr); 350 351 /* VGA is present! */ 352 return TRUE; 353 } 354 355 /* PUBLIC FUNCTIONS **********************************************************/ 356 357 /* 358 * @implemented 359 */ 360 BOOLEAN 361 NTAPI 362 VidInitialize( 363 _In_ BOOLEAN SetMode) 364 { 365 ULONG_PTR Context = 0; 366 PHYSICAL_ADDRESS TranslatedAddress; 367 PHYSICAL_ADDRESS NullAddress = {{0, 0}}, VgaAddress; 368 ULONG AddressSpace; 369 BOOLEAN Result; 370 ULONG_PTR Base; 371 372 /* Make sure that we have a bus translation function */ 373 if (!HalFindBusAddressTranslation) return FALSE; 374 375 /* Loop trying to find possible VGA base addresses */ 376 while (TRUE) 377 { 378 /* Get the VGA Register address */ 379 AddressSpace = 1; 380 Result = HalFindBusAddressTranslation(NullAddress, 381 &AddressSpace, 382 &TranslatedAddress, 383 &Context, 384 TRUE); 385 if (!Result) return FALSE; 386 387 /* See if this is I/O Space, which we need to map */ 388 if (!AddressSpace) 389 { 390 /* Map it */ 391 Base = (ULONG_PTR)MmMapIoSpace(TranslatedAddress, 0x400, MmNonCached); 392 } 393 else 394 { 395 /* The base is the translated address, no need to map I/O space */ 396 Base = TranslatedAddress.LowPart; 397 } 398 399 /* Try to see if this is VGA */ 400 VgaRegisterBase = Base; 401 if (VgaIsPresent()) 402 { 403 /* Translate the VGA Memory Address */ 404 VgaAddress.LowPart = MEM_VGA; 405 VgaAddress.HighPart = 0; 406 AddressSpace = 0; 407 Result = HalFindBusAddressTranslation(VgaAddress, 408 &AddressSpace, 409 &TranslatedAddress, 410 &Context, 411 FALSE); 412 if (Result) break; 413 } 414 else 415 { 416 /* It's not, so unmap the I/O space if we mapped it */ 417 if (!AddressSpace) MmUnmapIoSpace((PVOID)VgaRegisterBase, 0x400); 418 } 419 420 /* Continue trying to see if there's any other address */ 421 } 422 423 /* Success! See if this is I/O Space, which we need to map */ 424 if (!AddressSpace) 425 { 426 /* Map it */ 427 Base = (ULONG_PTR)MmMapIoSpace(TranslatedAddress, 428 MEM_VGA_SIZE, 429 MmNonCached); 430 } 431 else 432 { 433 /* The base is the translated address, no need to map I/O space */ 434 Base = TranslatedAddress.LowPart; 435 } 436 437 /* Set the VGA Memory Base */ 438 VgaBase = Base; 439 440 /* Now check if we have to set the mode */ 441 if (SetMode) 442 { 443 /* Clear the current position */ 444 VidpCurrentX = 0; 445 VidpCurrentY = 0; 446 447 /* Reset the display and initialize it */ 448 if (HalResetDisplay()) 449 { 450 /* The HAL handled the display, re-initialize only the AC registers */ 451 VgaInterpretCmdStream(AT_Initialization); 452 } 453 else 454 { 455 /* The HAL didn't handle the display, fully re-initialize the VGA */ 456 VgaInterpretCmdStream(VGA_640x480); 457 } 458 } 459 460 /* VGA is ready */ 461 return TRUE; 462 } 463 464 /* 465 * @implemented 466 */ 467 VOID 468 NTAPI 469 VidResetDisplay( 470 _In_ BOOLEAN HalReset) 471 { 472 /* Clear the current position */ 473 VidpCurrentX = 0; 474 VidpCurrentY = 0; 475 476 /* Clear the screen with HAL if we were asked to */ 477 if (HalReset) 478 { 479 if (!HalResetDisplay()) 480 { 481 /* The HAL didn't handle the display, fully re-initialize the VGA */ 482 VgaInterpretCmdStream(VGA_640x480); 483 } 484 } 485 486 /* Always re-initialize the AC registers */ 487 VgaInterpretCmdStream(AT_Initialization); 488 489 /* Re-initialize the palette and fill the screen black */ 490 InitializePalette(); 491 VidSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_BLACK); 492 } 493