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 61 /* PRIVATE FUNCTIONS *********************************************************/ 62 63 static VOID 64 NTAPI 65 ReadWriteMode( 66 _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 /* Dummy read to load latch registers */ \ 98 (VOID)READ_REGISTER_UCHAR((_PixelPtr)); \ 99 /* Set the new color */ \ 100 WRITE_REGISTER_UCHAR((_PixelPtr), (UCHAR)(_TextColor)); \ 101 } while (0); 102 103 VOID 104 NTAPI 105 DisplayCharacter( 106 _In_ CHAR Character, 107 _In_ ULONG Left, 108 _In_ ULONG Top, 109 _In_ ULONG TextColor, 110 _In_ ULONG BackColor) 111 { 112 PUCHAR FontChar, PixelPtr; 113 ULONG Height; 114 UCHAR Shift; 115 116 PrepareForSetPixel(); 117 118 /* Calculate shift */ 119 Shift = Left & 7; 120 121 /* Get the font and pixel pointer */ 122 FontChar = GetFontPtr(Character); 123 PixelPtr = (PUCHAR)(VgaBase + (Left >> 3) + (Top * (SCREEN_WIDTH / 8))); 124 125 /* Loop all pixel rows */ 126 for (Height = BOOTCHAR_HEIGHT; Height > 0; --Height) 127 { 128 SET_PIXELS(PixelPtr, *FontChar >> Shift, TextColor); 129 PixelPtr += (SCREEN_WIDTH / 8); 130 FontChar += FONT_PTR_DELTA; 131 } 132 133 /* Check if we need to update neighbor bytes */ 134 if (Shift) 135 { 136 /* Calculate shift for 2nd byte */ 137 Shift = 8 - Shift; 138 139 /* Get the font and pixel pointer (2nd byte) */ 140 FontChar = GetFontPtr(Character); 141 PixelPtr = (PUCHAR)(VgaBase + (Left >> 3) + (Top * (SCREEN_WIDTH / 8)) + 1); 142 143 /* Loop all pixel rows */ 144 for (Height = BOOTCHAR_HEIGHT; Height > 0; --Height) 145 { 146 SET_PIXELS(PixelPtr, *FontChar << Shift, TextColor); 147 PixelPtr += (SCREEN_WIDTH / 8); 148 FontChar += FONT_PTR_DELTA; 149 } 150 } 151 152 /* Check if the background color is transparent */ 153 if (BackColor >= BV_COLOR_NONE) 154 { 155 /* We are done */ 156 return; 157 } 158 159 /* Calculate shift */ 160 Shift = Left & 7; 161 162 /* Get the font and pixel pointer */ 163 FontChar = GetFontPtr(Character); 164 PixelPtr = (PUCHAR)(VgaBase + (Left >> 3) + (Top * (SCREEN_WIDTH / 8))); 165 166 /* Loop all pixel rows */ 167 for (Height = BOOTCHAR_HEIGHT; Height > 0; --Height) 168 { 169 SET_PIXELS(PixelPtr, ~*FontChar >> Shift, BackColor); 170 PixelPtr += (SCREEN_WIDTH / 8); 171 FontChar += FONT_PTR_DELTA; 172 } 173 174 /* Check if we need to update neighbor bytes */ 175 if (Shift) 176 { 177 /* Calculate shift for 2nd byte */ 178 Shift = 8 - Shift; 179 180 /* Get the font and pixel pointer (2nd byte) */ 181 FontChar = GetFontPtr(Character); 182 PixelPtr = (PUCHAR)(VgaBase + (Left >> 3) + (Top * (SCREEN_WIDTH / 8)) + 1); 183 184 /* Loop all pixel rows */ 185 for (Height = BOOTCHAR_HEIGHT; Height > 0; --Height) 186 { 187 SET_PIXELS(PixelPtr, ~*FontChar << Shift, BackColor); 188 PixelPtr += (SCREEN_WIDTH / 8); 189 FontChar += FONT_PTR_DELTA; 190 } 191 } 192 } 193 194 static VOID 195 NTAPI 196 SetPaletteEntryRGB( 197 _In_ ULONG Id, 198 _In_ RGBQUAD Rgb) 199 { 200 /* Set the palette index */ 201 __outpb(VGA_BASE_IO_PORT + DAC_ADDRESS_WRITE_PORT, (UCHAR)Id); 202 203 /* Set RGB colors */ 204 __outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, GetRValue(Rgb) >> 2); 205 __outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, GetGValue(Rgb) >> 2); 206 __outpb(VGA_BASE_IO_PORT + DAC_DATA_REG_PORT, GetBValue(Rgb) >> 2); 207 } 208 209 VOID 210 NTAPI 211 InitPaletteWithTable( 212 _In_ PULONG Table, 213 _In_ ULONG Count) 214 { 215 ULONG i; 216 PULONG Entry = Table; 217 218 for (i = 0; i < Count; i++, Entry++) 219 { 220 SetPaletteEntryRGB(i, *Entry); 221 } 222 } 223 224 VOID 225 NTAPI 226 DoScroll( 227 _In_ ULONG Scroll) 228 { 229 ULONG Top, RowSize; 230 PUCHAR OldPosition, NewPosition; 231 232 /* Clear the 4 planes */ 233 __outpw(VGA_BASE_IO_PORT + SEQ_ADDRESS_PORT, 0x0F02); 234 235 /* Set the bitmask to 0xFF for all 4 planes */ 236 __outpw(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, 0xFF08); 237 238 /* Set Mode 1 */ 239 ReadWriteMode(1); 240 241 RowSize = (VidpScrollRegion[2] - VidpScrollRegion[0] + 1) / 8; 242 243 /* Calculate the position in memory for the row */ 244 OldPosition = (PUCHAR)(VgaBase + (VidpScrollRegion[1] + Scroll) * (SCREEN_WIDTH / 8) + VidpScrollRegion[0] / 8); 245 NewPosition = (PUCHAR)(VgaBase + VidpScrollRegion[1] * (SCREEN_WIDTH / 8) + VidpScrollRegion[0] / 8); 246 247 /* Start loop */ 248 for (Top = VidpScrollRegion[1]; Top <= VidpScrollRegion[3]; ++Top) 249 { 250 #if defined(_M_IX86) || defined(_M_AMD64) 251 __movsb(NewPosition, OldPosition, RowSize); 252 #else 253 ULONG i; 254 255 /* Scroll the row */ 256 for (i = 0; i < RowSize; ++i) 257 WRITE_REGISTER_UCHAR(NewPosition + i, READ_REGISTER_UCHAR(OldPosition + i)); 258 #endif 259 OldPosition += (SCREEN_WIDTH / 8); 260 NewPosition += (SCREEN_WIDTH / 8); 261 } 262 } 263 264 VOID 265 NTAPI 266 PreserveRow( 267 _In_ ULONG CurrentTop, 268 _In_ ULONG TopDelta, 269 _In_ BOOLEAN Restore) 270 { 271 PUCHAR Position1, Position2; 272 ULONG Count; 273 274 /* Clear the 4 planes */ 275 __outpw(VGA_BASE_IO_PORT + SEQ_ADDRESS_PORT, 0x0F02); 276 277 /* Set the bitmask to 0xFF for all 4 planes */ 278 __outpw(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, 0xFF08); 279 280 /* Set Mode 1 */ 281 ReadWriteMode(1); 282 283 /* Calculate the position in memory for the row */ 284 if (Restore) 285 { 286 /* Restore the row by copying back the contents saved off-screen */ 287 Position1 = (PUCHAR)(VgaBase + CurrentTop * (SCREEN_WIDTH / 8)); 288 Position2 = (PUCHAR)(VgaBase + SCREEN_HEIGHT * (SCREEN_WIDTH / 8)); 289 } 290 else 291 { 292 /* Preserve the row by saving its contents off-screen */ 293 Position1 = (PUCHAR)(VgaBase + SCREEN_HEIGHT * (SCREEN_WIDTH / 8)); 294 Position2 = (PUCHAR)(VgaBase + CurrentTop * (SCREEN_WIDTH / 8)); 295 } 296 297 /* Set the count and loop every pixel */ 298 Count = TopDelta * (SCREEN_WIDTH / 8); 299 #if defined(_M_IX86) || defined(_M_AMD64) 300 __movsb(Position1, Position2, Count); 301 #else 302 while (Count--) 303 { 304 /* Write the data back on the other position */ 305 WRITE_REGISTER_UCHAR(Position1, READ_REGISTER_UCHAR(Position2)); 306 307 /* Increase both positions */ 308 Position1++; 309 Position2++; 310 } 311 #endif 312 } 313 314 /* PUBLIC FUNCTIONS **********************************************************/ 315 316 /* 317 * @implemented 318 */ 319 VOID 320 NTAPI 321 VidCleanUp(VOID) 322 { 323 /* Select bit mask register and clear it */ 324 __outpb(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, IND_BIT_MASK); 325 __outpb(VGA_BASE_IO_PORT + GRAPH_DATA_PORT, BIT_MASK_DEFAULT); 326 } 327 328 /* 329 * @implemented 330 */ 331 VOID 332 NTAPI 333 VidScreenToBufferBlt( 334 _Out_writes_bytes_(Delta * Height) PUCHAR Buffer, 335 _In_ ULONG Left, 336 _In_ ULONG Top, 337 _In_ ULONG Width, 338 _In_ ULONG Height, 339 _In_ ULONG Delta) 340 { 341 ULONG Plane; 342 ULONG XDistance; 343 ULONG LeftDelta, RightDelta; 344 ULONG PixelOffset; 345 PUCHAR PixelPosition; 346 PUCHAR k, i; 347 PULONG m; 348 UCHAR Value, Value2; 349 UCHAR a; 350 ULONG b; 351 ULONG x, y; 352 353 /* Calculate total distance to copy on X */ 354 XDistance = Left + Width - 1; 355 356 /* Calculate the 8-byte left and right deltas */ 357 LeftDelta = Left & 7; 358 RightDelta = 8 - LeftDelta; 359 360 /* Clear the destination buffer */ 361 RtlZeroMemory(Buffer, Delta * Height); 362 363 /* Calculate the pixel offset and convert the X distance into byte form */ 364 PixelOffset = Top * (SCREEN_WIDTH / 8) + (Left >> 3); 365 XDistance >>= 3; 366 367 /* Loop the 4 planes */ 368 for (Plane = 0; Plane < 4; ++Plane) 369 { 370 /* Set the current pixel position and reset buffer loop variable */ 371 PixelPosition = (PUCHAR)(VgaBase + PixelOffset); 372 i = Buffer; 373 374 /* Set Mode 0 */ 375 ReadWriteMode(0); 376 377 /* Set the current plane */ 378 __outpw(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, (Plane << 8) | IND_READ_MAP); 379 380 /* Start the outer Y height loop */ 381 for (y = Height; y > 0; --y) 382 { 383 /* Read the current value */ 384 m = (PULONG)i; 385 Value = READ_REGISTER_UCHAR(PixelPosition); 386 387 /* Set Pixel Position loop variable */ 388 k = PixelPosition + 1; 389 390 /* Check if we're still within bounds */ 391 if (Left <= XDistance) 392 { 393 /* Start the X inner loop */ 394 for (x = (XDistance - Left) + 1; x > 0; --x) 395 { 396 /* Read the current value */ 397 Value2 = READ_REGISTER_UCHAR(k); 398 399 /* Increase pixel position */ 400 k++; 401 402 /* Do the blt */ 403 a = Value2 >> (UCHAR)RightDelta; 404 a |= Value << (UCHAR)LeftDelta; 405 b = lookup[a & 0xF]; 406 a >>= 4; 407 b <<= 16; 408 b |= lookup[a]; 409 410 /* Save new value to buffer */ 411 *m |= (b << Plane); 412 413 /* Move to next destination location */ 414 m++; 415 416 /* Write new value */ 417 Value = Value2; 418 } 419 } 420 421 /* Update pixel position */ 422 PixelPosition += (SCREEN_WIDTH / 8); 423 i += Delta; 424 } 425 } 426 } 427 428 /* 429 * @implemented 430 */ 431 VOID 432 NTAPI 433 VidSolidColorFill( 434 _In_ ULONG Left, 435 _In_ ULONG Top, 436 _In_ ULONG Right, 437 _In_ ULONG Bottom, 438 _In_ UCHAR Color) 439 { 440 ULONG rMask, lMask; 441 ULONG LeftOffset, RightOffset, Distance; 442 PUCHAR Offset; 443 ULONG i, j; 444 445 /* Get the left and right masks, shifts, and delta */ 446 LeftOffset = Left >> 3; 447 lMask = (lMaskTable[Left & 0x7] << 8) | IND_BIT_MASK; 448 RightOffset = Right >> 3; 449 rMask = (rMaskTable[Right & 0x7] << 8) | IND_BIT_MASK; 450 Distance = RightOffset - LeftOffset; 451 452 /* If there is no distance, then combine the right and left masks */ 453 if (!Distance) lMask &= rMask; 454 455 PrepareForSetPixel(); 456 457 /* Calculate pixel position for the read */ 458 Offset = (PUCHAR)(VgaBase + (Top * (SCREEN_WIDTH / 8)) + LeftOffset); 459 460 /* Select the bitmask register and write the mask */ 461 __outpw(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, (USHORT)lMask); 462 463 /* Check if the top coord is below the bottom one */ 464 if (Top <= Bottom) 465 { 466 /* Start looping each line */ 467 for (i = (Bottom - Top) + 1; i > 0; --i) 468 { 469 /* Read the previous value and add our color */ 470 WRITE_REGISTER_UCHAR(Offset, READ_REGISTER_UCHAR(Offset) & Color); 471 472 /* Move to the next line */ 473 Offset += (SCREEN_WIDTH / 8); 474 } 475 } 476 477 /* Check if we have a delta */ 478 if (Distance > 0) 479 { 480 /* Calculate new pixel position */ 481 Offset = (PUCHAR)(VgaBase + (Top * (SCREEN_WIDTH / 8)) + RightOffset); 482 Distance--; 483 484 /* Select the bitmask register and write the mask */ 485 __outpw(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, (USHORT)rMask); 486 487 /* Check if the top coord is below the bottom one */ 488 if (Top <= Bottom) 489 { 490 /* Start looping each line */ 491 for (i = (Bottom - Top) + 1; i > 0; --i) 492 { 493 /* Read the previous value and add our color */ 494 WRITE_REGISTER_UCHAR(Offset, READ_REGISTER_UCHAR(Offset) & Color); 495 496 /* Move to the next line */ 497 Offset += (SCREEN_WIDTH / 8); 498 } 499 } 500 501 /* Check if we still have a delta */ 502 if (Distance > 0) 503 { 504 /* Calculate new pixel position */ 505 Offset = (PUCHAR)(VgaBase + (Top * (SCREEN_WIDTH / 8)) + LeftOffset + 1); 506 507 /* Set the bitmask to 0xFF for all 4 planes */ 508 __outpw(VGA_BASE_IO_PORT + GRAPH_ADDRESS_PORT, 0xFF08); 509 510 /* Check if the top coord is below the bottom one */ 511 if (Top <= Bottom) 512 { 513 /* Start looping each line */ 514 for (i = (Bottom - Top) + 1; i > 0; --i) 515 { 516 /* Loop the shift delta */ 517 for (j = Distance; j > 0; Offset++, --j) 518 { 519 /* Write the color */ 520 WRITE_REGISTER_UCHAR(Offset, Color); 521 } 522 523 /* Update position in memory */ 524 Offset += ((SCREEN_WIDTH / 8) - Distance); 525 } 526 } 527 } 528 } 529 } 530