1 #include "precomp.h" 2 3 /* GLOBALS *******************************************************************/ 4 5 static UCHAR lMaskTable[8] = 6 { 7 (1 << 8) - (1 << 0), 8 (1 << 7) - (1 << 0), 9 (1 << 6) - (1 << 0), 10 (1 << 5) - (1 << 0), 11 (1 << 4) - (1 << 0), 12 (1 << 3) - (1 << 0), 13 (1 << 2) - (1 << 0), 14 (1 << 1) - (1 << 0) 15 }; 16 static UCHAR rMaskTable[8] = 17 { 18 (1 << 7), 19 (1 << 7) + (1 << 6), 20 (1 << 7) + (1 << 6) + (1 << 5), 21 (1 << 7) + (1 << 6) + (1 << 5) + (1 << 4), 22 (1 << 7) + (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3), 23 (1 << 7) + (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3) + (1 << 2), 24 (1 << 7) + (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3) + (1 << 2) + (1 << 1), 25 (1 << 7) + (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3) + (1 << 2) + (1 << 1) + (1 << 0), 26 }; 27 UCHAR PixelMask[8] = 28 { 29 (1 << 7), 30 (1 << 6), 31 (1 << 5), 32 (1 << 4), 33 (1 << 3), 34 (1 << 2), 35 (1 << 1), 36 (1 << 0), 37 }; 38 static ULONG lookup[16] = 39 { 40 0x0000, 41 0x0100, 42 0x1000, 43 0x1100, 44 0x0001, 45 0x0101, 46 0x1001, 47 0x1101, 48 0x0010, 49 0x0110, 50 0x1010, 51 0x1110, 52 0x0011, 53 0x0111, 54 0x1011, 55 0x1111, 56 }; 57 58 ULONG_PTR VgaRegisterBase = 0; 59 ULONG_PTR VgaBase = 0; 60 static BOOLEAN ClearRow = FALSE; 61 62 /* PRIVATE FUNCTIONS *********************************************************/ 63 64 static VOID 65 NTAPI 66 ReadWriteMode(IN UCHAR Mode) 67 { 68 UCHAR Value; 69 70 /* Switch to graphics mode register */ 71 __outpb(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, IND_GRAPH_MODE); 72 73 /* Get the current register value, minus the current mode */ 74 Value = __inpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT) & 0xF4; 75 76 /* Set the new mode */ 77 __outpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT, Mode | Value); 78 } 79 80 VOID 81 PrepareForSetPixel(VOID) 82 { 83 /* Switch to mode 10 */ 84 ReadWriteMode(10); 85 86 /* Clear the 4 planes (we're already in unchained mode here) */ 87 __outpw(VGA_BASE_IO_PORT + SEQ_ADDRESS_PORT, 0x0F02); 88 89 /* Select the color don't care register */ 90 __outpw(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, 7); 91 } 92 93 #define SET_PIXELS(_PixelPtr, _PixelMask, _TextColor) \ 94 do { \ 95 /* Select the bitmask register and write the mask */ \ 96 __outpw(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, ((_PixelMask) << 8) | IND_BIT_MASK); \ 97 /* Set the new color */ \ 98 WRITE_REGISTER_UCHAR((_PixelPtr), (UCHAR)(_TextColor)); \ 99 } while (0); 100 101 #ifdef CHAR_GEN_UPSIDE_DOWN 102 # define GetFontPtr(_Char) &FontData[_Char * BOOTCHAR_HEIGHT] + BOOTCHAR_HEIGHT - 1; 103 # define FONT_PTR_DELTA (-1) 104 #else 105 # define GetFontPtr(_Char) &FontData[_Char * BOOTCHAR_HEIGHT]; 106 # define FONT_PTR_DELTA (1) 107 #endif 108 109 VOID 110 NTAPI 111 DisplayCharacter( 112 _In_ CHAR Character, 113 _In_ ULONG Left, 114 _In_ ULONG Top, 115 _In_ ULONG TextColor, 116 _In_ ULONG BackColor) 117 { 118 PUCHAR FontChar, PixelPtr; 119 ULONG Height; 120 UCHAR Shift; 121 122 PrepareForSetPixel(); 123 124 /* Calculate shift */ 125 Shift = Left & 7; 126 127 /* Get the font and pixel pointer */ 128 FontChar = GetFontPtr(Character); 129 PixelPtr = (PUCHAR)(VgaBase + (Left >> 3) + (Top * (SCREEN_WIDTH / 8))); 130 131 /* Loop all pixel rows */ 132 for (Height = BOOTCHAR_HEIGHT; Height > 0; --Height) 133 { 134 SET_PIXELS(PixelPtr, *FontChar >> Shift, TextColor); 135 PixelPtr += (SCREEN_WIDTH / 8); 136 FontChar += FONT_PTR_DELTA; 137 } 138 139 /* Check if we need to update neighbor bytes */ 140 if (Shift) 141 { 142 /* Calculate shift for 2nd byte */ 143 Shift = 8 - Shift; 144 145 /* Get the font and pixel pointer (2nd byte) */ 146 FontChar = GetFontPtr(Character); 147 PixelPtr = (PUCHAR)(VgaBase + (Left >> 3) + (Top * (SCREEN_WIDTH / 8)) + 1); 148 149 /* Loop all pixel rows */ 150 for (Height = BOOTCHAR_HEIGHT; Height > 0; --Height) 151 { 152 SET_PIXELS(PixelPtr, *FontChar << Shift, TextColor); 153 PixelPtr += (SCREEN_WIDTH / 8); 154 FontChar += FONT_PTR_DELTA; 155 } 156 } 157 158 /* Check if the background color is transparent */ 159 if (BackColor >= 16) 160 { 161 /* We are done */ 162 return; 163 } 164 165 /* Calculate shift */ 166 Shift = Left & 7; 167 168 /* Get the font and pixel pointer */ 169 FontChar = GetFontPtr(Character); 170 PixelPtr = (PUCHAR)(VgaBase + (Left >> 3) + (Top * (SCREEN_WIDTH / 8))); 171 172 /* Loop all pixel rows */ 173 for (Height = BOOTCHAR_HEIGHT; Height > 0; --Height) 174 { 175 SET_PIXELS(PixelPtr, ~*FontChar >> Shift, BackColor); 176 PixelPtr += (SCREEN_WIDTH / 8); 177 FontChar += FONT_PTR_DELTA; 178 } 179 180 /* Check if we need to update neighbor bytes */ 181 if (Shift) 182 { 183 /* Calculate shift for 2nd byte */ 184 Shift = 8 - Shift; 185 186 /* Get the font and pixel pointer (2nd byte) */ 187 FontChar = GetFontPtr(Character); 188 PixelPtr = (PUCHAR)(VgaBase + (Left >> 3) + (Top * (SCREEN_WIDTH / 8)) + 1); 189 190 /* Loop all pixel rows */ 191 for (Height = BOOTCHAR_HEIGHT; Height > 0; --Height) 192 { 193 SET_PIXELS(PixelPtr, ~*FontChar << Shift, BackColor); 194 PixelPtr += (SCREEN_WIDTH / 8); 195 FontChar += FONT_PTR_DELTA; 196 } 197 } 198 } 199 200 static VOID 201 NTAPI 202 SetPaletteEntryRGB(IN ULONG Id, 203 IN ULONG Rgb) 204 { 205 PCHAR Colors = (PCHAR)&Rgb; 206 207 /* Set the palette index */ 208 __outpb(VGA_BASE_IO_PORT + DAC_ADDRESS_WRITE_PORT, (UCHAR)Id); 209 210 /* Set RGB colors */ 211 __outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, Colors[2] >> 2); 212 __outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, Colors[1] >> 2); 213 __outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, Colors[0] >> 2); 214 } 215 216 VOID 217 NTAPI 218 InitPaletteWithTable( 219 _In_ PULONG Table, 220 _In_ ULONG Count) 221 { 222 ULONG i; 223 PULONG Entry = Table; 224 225 /* Loop every entry */ 226 for (i = 0; i < Count; i++, Entry++) 227 { 228 /* Set the entry */ 229 SetPaletteEntryRGB(i, *Entry); 230 } 231 } 232 233 static VOID 234 NTAPI 235 SetPaletteEntry(IN ULONG Id, 236 IN ULONG PaletteEntry) 237 { 238 /* Set the palette index */ 239 __outpb(VGA_BASE_IO_PORT + DAC_ADDRESS_WRITE_PORT, (UCHAR)Id); 240 241 /* Set RGB colors */ 242 __outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, PaletteEntry & 0xFF); 243 __outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, (PaletteEntry >>= 8) & 0xFF); 244 __outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, (PaletteEntry >> 8) & 0xFF); 245 } 246 247 VOID 248 NTAPI 249 InitializePalette(VOID) 250 { 251 ULONG PaletteEntry[16] = {0x000000, 252 0x000020, 253 0x002000, 254 0x002020, 255 0x200000, 256 0x200020, 257 0x202000, 258 0x202020, 259 0x303030, 260 0x00003F, 261 0x003F00, 262 0x003F3F, 263 0x3F0000, 264 0x3F003F, 265 0x3F3F00, 266 0x3F3F3F}; 267 ULONG i; 268 269 /* Loop all the entries and set their palettes */ 270 for (i = 0; i < 16; i++) SetPaletteEntry(i, PaletteEntry[i]); 271 } 272 273 static VOID 274 NTAPI 275 VgaScroll(IN ULONG Scroll) 276 { 277 ULONG Top, RowSize; 278 PUCHAR OldPosition, NewPosition; 279 280 /* Clear the 4 planes */ 281 __outpw(VGA_BASE_IO_PORT + SEQ_ADDRESS_PORT, 0x0F02); 282 283 /* Set the bitmask to 0xFF for all 4 planes */ 284 __outpw(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, 0xFF08); 285 286 /* Set Mode 1 */ 287 ReadWriteMode(1); 288 289 RowSize = (VidpScrollRegion[2] - VidpScrollRegion[0] + 1) / 8; 290 291 /* Calculate the position in memory for the row */ 292 OldPosition = (PUCHAR)(VgaBase + (VidpScrollRegion[1] + Scroll) * (SCREEN_WIDTH / 8) + VidpScrollRegion[0] / 8); 293 NewPosition = (PUCHAR)(VgaBase + VidpScrollRegion[1] * (SCREEN_WIDTH / 8) + VidpScrollRegion[0] / 8); 294 295 /* Start loop */ 296 for (Top = VidpScrollRegion[1]; Top <= VidpScrollRegion[3]; ++Top) 297 { 298 #if defined(_M_IX86) || defined(_M_AMD64) 299 __movsb(NewPosition, OldPosition, RowSize); 300 #else 301 ULONG i; 302 303 /* Scroll the row */ 304 for (i = 0; i < RowSize; ++i) 305 WRITE_REGISTER_UCHAR(NewPosition + i, READ_REGISTER_UCHAR(OldPosition + i)); 306 #endif 307 OldPosition += (SCREEN_WIDTH / 8); 308 NewPosition += (SCREEN_WIDTH / 8); 309 } 310 } 311 312 static VOID 313 NTAPI 314 PreserveRow(IN ULONG CurrentTop, 315 IN ULONG TopDelta, 316 IN BOOLEAN Restore) 317 { 318 PUCHAR Position1, Position2; 319 ULONG Count; 320 321 /* Clear the 4 planes */ 322 __outpw(VGA_BASE_IO_PORT + SEQ_ADDRESS_PORT, 0x0F02); 323 324 /* Set the bitmask to 0xFF for all 4 planes */ 325 __outpw(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, 0xFF08); 326 327 /* Set Mode 1 */ 328 ReadWriteMode(1); 329 330 /* Calculate the position in memory for the row */ 331 if (Restore) 332 { 333 /* Restore the row by copying back the contents saved off-screen */ 334 Position1 = (PUCHAR)(VgaBase + CurrentTop * (SCREEN_WIDTH / 8)); 335 Position2 = (PUCHAR)(VgaBase + SCREEN_HEIGHT * (SCREEN_WIDTH / 8)); 336 } 337 else 338 { 339 /* Preserve the row by saving its contents off-screen */ 340 Position1 = (PUCHAR)(VgaBase + SCREEN_HEIGHT * (SCREEN_WIDTH / 8)); 341 Position2 = (PUCHAR)(VgaBase + CurrentTop * (SCREEN_WIDTH / 8)); 342 } 343 344 /* Set the count and loop every pixel */ 345 Count = TopDelta * (SCREEN_WIDTH / 8); 346 #if defined(_M_IX86) || defined(_M_AMD64) 347 __movsb(Position1, Position2, Count); 348 #else 349 while (Count--) 350 { 351 /* Write the data back on the other position */ 352 WRITE_REGISTER_UCHAR(Position1, READ_REGISTER_UCHAR(Position2)); 353 354 /* Increase both positions */ 355 Position1++; 356 Position2++; 357 } 358 #endif 359 } 360 361 /* PUBLIC FUNCTIONS **********************************************************/ 362 363 /* 364 * @implemented 365 */ 366 ULONG 367 NTAPI 368 VidSetTextColor(IN ULONG Color) 369 { 370 ULONG OldColor; 371 372 /* Save the old color and set the new one */ 373 OldColor = VidpTextColor; 374 VidpTextColor = Color; 375 return OldColor; 376 } 377 378 /* 379 * @implemented 380 */ 381 VOID 382 NTAPI 383 VidCleanUp(VOID) 384 { 385 /* Select bit mask register and clear it */ 386 __outpb(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, IND_BIT_MASK); 387 __outpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT, BIT_MASK_DEFAULT); 388 } 389 390 /* 391 * @implemented 392 */ 393 VOID 394 NTAPI 395 VidDisplayString(IN PUCHAR String) 396 { 397 ULONG TopDelta = BOOTCHAR_HEIGHT + 1; 398 399 /* Start looping the string */ 400 for (; *String; ++String) 401 { 402 /* Treat new-line separately */ 403 if (*String == '\n') 404 { 405 /* Modify Y position */ 406 VidpCurrentY += TopDelta; 407 if (VidpCurrentY + TopDelta - 1 > VidpScrollRegion[3]) 408 { 409 /* Scroll the view and clear the current row */ 410 VgaScroll(TopDelta); 411 VidpCurrentY -= TopDelta; 412 PreserveRow(VidpCurrentY, TopDelta, TRUE); 413 } 414 else 415 { 416 /* Preserve the current row */ 417 PreserveRow(VidpCurrentY, TopDelta, FALSE); 418 } 419 420 /* Update current X */ 421 VidpCurrentX = VidpScrollRegion[0]; 422 423 /* No need to clear this row */ 424 ClearRow = FALSE; 425 } 426 else if (*String == '\r') 427 { 428 /* Update current X */ 429 VidpCurrentX = VidpScrollRegion[0]; 430 431 /* If a new-line does not follow we will clear the current row */ 432 if (String[1] != '\n') ClearRow = TRUE; 433 } 434 else 435 { 436 /* Clear the current row if we had a return-carriage without a new-line */ 437 if (ClearRow) 438 { 439 PreserveRow(VidpCurrentY, TopDelta, TRUE); 440 ClearRow = FALSE; 441 } 442 443 /* Display this character */ 444 DisplayCharacter(*String, VidpCurrentX, VidpCurrentY, VidpTextColor, 16); 445 VidpCurrentX += 8; 446 447 /* Check if we should scroll */ 448 if (VidpCurrentX + 7 > VidpScrollRegion[2]) 449 { 450 /* Update Y position and check if we should scroll it */ 451 VidpCurrentY += TopDelta; 452 if (VidpCurrentY + TopDelta - 1 > VidpScrollRegion[3]) 453 { 454 /* Scroll the view and clear the current row */ 455 VgaScroll(TopDelta); 456 VidpCurrentY -= TopDelta; 457 PreserveRow(VidpCurrentY, TopDelta, TRUE); 458 } 459 else 460 { 461 /* Preserve the current row */ 462 PreserveRow(VidpCurrentY, TopDelta, FALSE); 463 } 464 465 /* Update current X */ 466 VidpCurrentX = VidpScrollRegion[0]; 467 } 468 } 469 } 470 } 471 472 /* 473 * @implemented 474 */ 475 VOID 476 NTAPI 477 VidScreenToBufferBlt(OUT PUCHAR Buffer, 478 IN ULONG Left, 479 IN ULONG Top, 480 IN ULONG Width, 481 IN ULONG Height, 482 IN ULONG Delta) 483 { 484 ULONG Plane; 485 ULONG XDistance; 486 ULONG LeftDelta, RightDelta; 487 ULONG PixelOffset; 488 PUCHAR PixelPosition; 489 PUCHAR k, i; 490 PULONG m; 491 UCHAR Value, Value2; 492 UCHAR a; 493 ULONG b; 494 ULONG x, y; 495 496 /* Calculate total distance to copy on X */ 497 XDistance = Left + Width - 1; 498 499 /* Calculate the 8-byte left and right deltas */ 500 LeftDelta = Left & 7; 501 RightDelta = 8 - LeftDelta; 502 503 /* Clear the destination buffer */ 504 RtlZeroMemory(Buffer, Delta * Height); 505 506 /* Calculate the pixel offset and convert the X distance into byte form */ 507 PixelOffset = Top * (SCREEN_WIDTH / 8) + (Left >> 3); 508 XDistance >>= 3; 509 510 /* Loop the 4 planes */ 511 for (Plane = 0; Plane < 4; ++Plane) 512 { 513 /* Set the current pixel position and reset buffer loop variable */ 514 PixelPosition = (PUCHAR)(VgaBase + PixelOffset); 515 i = Buffer; 516 517 /* Set Mode 0 */ 518 ReadWriteMode(0); 519 520 /* Set the current plane */ 521 __outpw(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, (Plane << 8) | IND_READ_MAP); 522 523 /* Start the outer Y height loop */ 524 for (y = Height; y > 0; --y) 525 { 526 /* Read the current value */ 527 m = (PULONG)i; 528 Value = READ_REGISTER_UCHAR(PixelPosition); 529 530 /* Set Pixel Position loop variable */ 531 k = PixelPosition + 1; 532 533 /* Check if we're still within bounds */ 534 if (Left <= XDistance) 535 { 536 /* Start the X inner loop */ 537 for (x = (XDistance - Left) + 1; x > 0; --x) 538 { 539 /* Read the current value */ 540 Value2 = READ_REGISTER_UCHAR(k); 541 542 /* Increase pixel position */ 543 k++; 544 545 /* Do the blt */ 546 a = Value2 >> (UCHAR)RightDelta; 547 a |= Value << (UCHAR)LeftDelta; 548 b = lookup[a & 0xF]; 549 a >>= 4; 550 b <<= 16; 551 b |= lookup[a]; 552 553 /* Save new value to buffer */ 554 *m |= (b << Plane); 555 556 /* Move to next destination location */ 557 m++; 558 559 /* Write new value */ 560 Value = Value2; 561 } 562 } 563 564 /* Update pixel position */ 565 PixelPosition += (SCREEN_WIDTH / 8); 566 i += Delta; 567 } 568 } 569 } 570 571 /* 572 * @implemented 573 */ 574 VOID 575 NTAPI 576 VidSolidColorFill(IN ULONG Left, 577 IN ULONG Top, 578 IN ULONG Right, 579 IN ULONG Bottom, 580 IN UCHAR Color) 581 { 582 ULONG rMask, lMask; 583 ULONG LeftOffset, RightOffset, Distance; 584 PUCHAR Offset; 585 ULONG i, j; 586 587 /* Get the left and right masks, shifts, and delta */ 588 LeftOffset = Left >> 3; 589 lMask = (lMaskTable[Left & 0x7] << 8) | IND_BIT_MASK; 590 RightOffset = Right >> 3; 591 rMask = (rMaskTable[Right & 0x7] << 8) | IND_BIT_MASK; 592 Distance = RightOffset - LeftOffset; 593 594 /* If there is no distance, then combine the right and left masks */ 595 if (!Distance) lMask &= rMask; 596 597 PrepareForSetPixel(); 598 599 /* Calculate pixel position for the read */ 600 Offset = (PUCHAR)(VgaBase + (Top * (SCREEN_WIDTH / 8)) + LeftOffset); 601 602 /* Select the bitmask register and write the mask */ 603 __outpw(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, (USHORT)lMask); 604 605 /* Check if the top coord is below the bottom one */ 606 if (Top <= Bottom) 607 { 608 /* Start looping each line */ 609 for (i = (Bottom - Top) + 1; i > 0; --i) 610 { 611 /* Read the previous value and add our color */ 612 WRITE_REGISTER_UCHAR(Offset, READ_REGISTER_UCHAR(Offset) & Color); 613 614 /* Move to the next line */ 615 Offset += (SCREEN_WIDTH / 8); 616 } 617 } 618 619 /* Check if we have a delta */ 620 if (Distance > 0) 621 { 622 /* Calculate new pixel position */ 623 Offset = (PUCHAR)(VgaBase + (Top * (SCREEN_WIDTH / 8)) + RightOffset); 624 Distance--; 625 626 /* Select the bitmask register and write the mask */ 627 __outpw(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, (USHORT)rMask); 628 629 /* Check if the top coord is below the bottom one */ 630 if (Top <= Bottom) 631 { 632 /* Start looping each line */ 633 for (i = (Bottom - Top) + 1; i > 0; --i) 634 { 635 /* Read the previous value and add our color */ 636 WRITE_REGISTER_UCHAR(Offset, READ_REGISTER_UCHAR(Offset) & Color); 637 638 /* Move to the next line */ 639 Offset += (SCREEN_WIDTH / 8); 640 } 641 } 642 643 /* Check if we still have a delta */ 644 if (Distance > 0) 645 { 646 /* Calculate new pixel position */ 647 Offset = (PUCHAR)(VgaBase + (Top * (SCREEN_WIDTH / 8)) + LeftOffset + 1); 648 649 /* Set the bitmask to 0xFF for all 4 planes */ 650 __outpw(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, 0xFF08); 651 652 /* Check if the top coord is below the bottom one */ 653 if (Top <= Bottom) 654 { 655 /* Start looping each line */ 656 for (i = (Bottom - Top) + 1; i > 0; --i) 657 { 658 /* Loop the shift delta */ 659 for (j = Distance; j > 0; Offset++, --j) 660 { 661 /* Write the color */ 662 WRITE_REGISTER_UCHAR(Offset, Color); 663 } 664 665 /* Update position in memory */ 666 Offset += ((SCREEN_WIDTH / 8) - Distance); 667 } 668 } 669 } 670 } 671 } 672