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